Тестирование платы HiFive Unleashed с ядром Linux 5.2.9

PDF

Тесты выполнялись в локальной сети Gigabit Ethernet без сторонней нагрузки. Устройства были подключены к одному коммутатору D-Link. Управление платой HiFive Unleashed выполнялось по протоколу SSH. На плате была установлена ОС Linux с ядром версии 5.2.9, собранным специально для этой платы.

Измерение производительности с помощью iperf3

Тесты выполнялись при установленных по умолчанию параметрах сетевых интерфейсов, показанных ниже.

Хост HiFive

root@freedom-u540:~# ethtool eth0 
Settings for eth0: 
       Supported ports: [ TP MII ] 
       Supported link modes:   10baseT/Half 10baseT/Full  
                               100baseT/Half 100baseT/Full  
                               1000baseT/Half 1000baseT/Full  
       Supported pause frame use: Symmetric Receive-only 
       Supports auto-negotiation: Yes 
       Supported FEC modes: Not reported 
       Advertised link modes:  10baseT/Half 10baseT/Full  
                               100baseT/Half 100baseT/Full  
                               1000baseT/Half 1000baseT/Full  
       Advertised pause frame use: No 
       Advertised auto-negotiation: Yes 
       Advertised FEC modes: Not reported 
       Link partner advertised link modes:  10baseT/Half 10baseT/Full  
                                            100baseT/Half 100baseT/Full  
                                            1000baseT/Full  
       Link partner advertised pause frame use: Symmetric 
       Link partner advertised auto-negotiation: Yes 
       Link partner advertised FEC modes: Not reported 
       Speed: 1000Mb/s 
       Duplex: Full 
       Port: MII 
       PHYAD: 0 
       Transceiver: internal 
       Auto-negotiation: on 
       Link detected: yes

Хост x86_64

[root@Lhotze ~]# ethtool enp4s0 
Settings for enp4s0: 
       Supported ports: [ TP ] 
       Supported link modes:   10baseT/Half 10baseT/Full  
                               100baseT/Half 100baseT/Full  
                               1000baseT/Full  
       Supported pause frame use: Symmetric 
       Supports auto-negotiation: Yes 
       Supported FEC modes: Not reported 
       Advertised link modes:  10baseT/Half 10baseT/Full  
                               100baseT/Half 100baseT/Full  
                               1000baseT/Full  
       Advertised pause frame use: Symmetric 
       Advertised auto-negotiation: Yes 
       Advertised FEC modes: Not reported 
       Speed: 1000Mb/s 
       Duplex: Full 
       Port: Twisted Pair 
       PHYAD: 1 
       Transceiver: internal 
       Auto-negotiation: on 
       MDI-X: off (auto) 
       Supports Wake-on: pumbg 
       Wake-on: g 
       Current message level: 0x00000007 (7) 
                              drv probe link 
       Link detected: yes

Из приведенного вывода видно, что оба интерфейса работают в полнодуплексном режиме со скоростью линии 1000 Мбит/с.

Далее были выполнены два теста, в одном из которых хост HiFive выступал в качестве клиента, в другом был сервером. Скорость определялась с помощью программы iperf3 с принятыми по умолчанию параметрами (протокол TCP, скорость передачи не ограничена.

Клиент HiFive

Вывод клиента

root@freedom-u540:~# iperf3 -c 192.168.0.10 
Connecting to host 192.168.0.10, port 5201 
[  5] local 192.168.0.3 port 46756 connected to 192.168.0.10 port 5201 
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd 
[  5]   0.00-1.02   sec  15.1 MBytes   124 Mbits/sec    0    148 KBytes        
[  5]   1.02-2.03   sec  15.0 MBytes   125 Mbits/sec    0    157 KBytes        
[  5]   2.03-3.03   sec  15.0 MBytes   126 Mbits/sec    0    164 KBytes        
[  5]   3.03-4.04   sec  15.2 MBytes   126 Mbits/sec    0    181 KBytes        
[  5]   4.04-5.03   sec  15.0 MBytes   127 Mbits/sec    0    181 KBytes        
[  5]   5.03-6.01   sec  15.0 MBytes   128 Mbits/sec    0    181 KBytes        
[  5]   6.01-7.07   sec  16.2 MBytes   129 Mbits/sec    0    230 KBytes        
[  5]   7.07-8.06   sec  15.0 MBytes   127 Mbits/sec    0    230 KBytes        
[  5]   8.06-9.04   sec  15.0 MBytes   128 Mbits/sec    0    230 KBytes        
[  5]   9.04-10.03  sec  15.0 MBytes   127 Mbits/sec    0    230 KBytes        
- - - - - - - - - - - - - - - - - - - - - - - - - 
[ ID] Interval           Transfer     Bitrate         Retr 
[  5]   0.00-10.03  sec   152 MBytes   127 Mbits/sec    0             sender 
[  5]   0.00-10.04  sec   152 MBytes   127 Mbits/sec                  receiver 

iperf Done.

Вывод сервера

[root@Lhotze src]# iperf3 -s 
----------------------------------------------------------- 
Server listening on 5201 
----------------------------------------------------------- 
Accepted connection from 192.168.0.3, port 46754 
[  5] local 192.168.0.10 port 5201 connected to 192.168.0.3 port 46756 
[ ID] Interval           Transfer     Bitrate 
[  5]   0.00-1.00   sec  14.6 MBytes   123 Mbits/sec                   
[  5]   1.00-2.00   sec  14.9 MBytes   125 Mbits/sec                   
[  5]   2.00-3.00   sec  15.0 MBytes   126 Mbits/sec                   
[  5]   3.00-4.00   sec  15.1 MBytes   126 Mbits/sec                   
[  5]   4.00-5.00   sec  15.2 MBytes   127 Mbits/sec                   
[  5]   5.00-6.00   sec  15.3 MBytes   129 Mbits/sec                   
[  5]   6.00-7.00   sec  15.3 MBytes   129 Mbits/sec                   
[  5]   7.00-8.00   sec  15.1 MBytes   127 Mbits/sec                   
[  5]   8.00-9.00   sec  15.3 MBytes   128 Mbits/sec                   
[  5]   9.00-10.00  sec  15.1 MBytes   127 Mbits/sec                   
[  5]  10.00-10.04  sec   665 KBytes   128 Mbits/sec                   
- - - - - - - - - - - - - - - - - - - - - - - - - 
[ ID] Interval           Transfer     Bitrate 
[  5]   0.00-10.04  sec   152 MBytes   127 Mbits/sec                  receiver 
-----------------------------------------------------------

Результат показывает среднюю скорость обмена через сеть 127 Мбит/с, что составляет лишь 12,7% от номинальной скорости линии. Вариации скорости в процессе измерения невелики, а объем переданных данных составил 152 Мбайта, что позволяет считать результат измерения достаточно достоверным.

Для выяснения причин столь малой скорости меняем роли участвующих в тесте хостов — HiFive становится сервером, а x86_64 — клиентом.

Сервер HiFive

Вывод сервера

root@freedom-u540:~# iperf3 -s              
----------------------------------------------------------- 
Server listening on 5201 
----------------------------------------------------------- 
Accepted connection from 192.168.0.10, port 55746 
[  5] local 192.168.0.3 port 5201 connected to 192.168.0.10 port 55748 
[ ID] Interval           Transfer     Bitrate 
[  5]   0.00-1.00   sec  26.2 MBytes   220 Mbits/sec                   
[  5]   1.00-2.00   sec  25.9 MBytes   217 Mbits/sec                   
[  5]   2.00-3.00   sec  25.6 MBytes   215 Mbits/sec                   
[  5]   3.00-4.00   sec  26.2 MBytes   220 Mbits/sec                   
[  5]   4.00-5.00   sec  25.9 MBytes   217 Mbits/sec                   
[  5]   5.00-6.00   sec  29.8 MBytes   250 Mbits/sec                   
[  5]   6.00-7.00   sec  28.5 MBytes   240 Mbits/sec                   
[  5]   7.00-8.00   sec  25.8 MBytes   216 Mbits/sec                   
[  5]   8.00-9.00   sec  26.1 MBytes   219 Mbits/sec                   
[  5]   9.00-10.00  sec  25.8 MBytes   217 Mbits/sec                   
[  5]  10.00-10.02  sec   580 KBytes   259 Mbits/sec                   
- - - - - - - - - - - - - - - - - - - - - - - - - 
[ ID] Interval           Transfer     Bitrate 
[  5]   0.00-10.02  sec   266 MBytes   223 Mbits/sec                  receiver 
----------------------------------------------------------- 
Server listening on 5201 
-----------------------------------------------------------

Вывод клиента

[root@Lhotze src]# iperf3 -c 192.168.0.3 
Connecting to host 192.168.0.3, port 5201 
[  5] local 192.168.0.10 port 55748 connected to 192.168.0.3 port 5201 
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd 
[  5]   0.00-1.00   sec  28.9 MBytes   242 Mbits/sec   27    527 KBytes        
[  5]   1.00-2.00   sec  26.2 MBytes   220 Mbits/sec    0    595 KBytes        
[  5]   2.00-3.00   sec  26.2 MBytes   220 Mbits/sec    0    645 KBytes        
[  5]   3.00-4.00   sec  26.2 MBytes   220 Mbits/sec    1    485 KBytes        
[  5]   4.00-5.00   sec  25.0 MBytes   210 Mbits/sec    0    522 KBytes        
[  5]   5.00-6.00   sec  30.0 MBytes   252 Mbits/sec    0    563 KBytes        
[  5]   6.00-7.00   sec  28.8 MBytes   241 Mbits/sec    0    601 KBytes        
[  5]   7.00-8.00   sec  26.2 MBytes   220 Mbits/sec    0    634 KBytes        
[  5]   8.00-9.00   sec  25.0 MBytes   210 Mbits/sec    1    471 KBytes        
[  5]   9.00-10.00  sec  26.2 MBytes   220 Mbits/sec    0    542 KBytes        
- - - - - - - - - - - - - - - - - - - - - - - - - 
[ ID] Interval           Transfer     Bitrate         Retr 
[  5]   0.00-10.00  sec   269 MBytes   226 Mbits/sec   29             sender 
[  5]   0.00-10.02  sec   266 MBytes   223 Mbits/sec                  receiver 

iperf Done.

В этом случае скорость получается почти вдвое выше, но все равно составляет лишь 22,3% от номинальной. Однако при внимательном рассмотрении вывода видно, что используемое отправителем (клиент) окно контроля насыщения TCP (правый столбец вывода на стороне клиента — Cwnd) существенно отличалось. Клиент HiFive задавал cwnd от 148 до 230 кбайт, а клиент x86_64 — от 471 до 645 кбайт. Это наводит на мысль о том, что скорость, определяемая iperf3 ограничивалась не на физическом или канальном уровне, а на транспортном (TCP). Отметим это и двинемся дальше.

Зависимость от физических параметров интерфейсов

Устанавливаем на сервере HiFive скорость сетевого интерфейса 100 и 10 Мбит,с и повторяем тесты. Параметры интерфейса на клиенте не изменяются.

Вывод сервера

root@freedom-u540:~# ethtool -s eth0 speed 100 autoneg off 

root@freedom-u540:~# iperf3 -s                 
----------------------------------------------------------- 
Server listening on 5201 
----------------------------------------------------------- 
Accepted connection from 192.168.0.10, port 38296 
[  5] local 192.168.0.3 port 5201 connected to 192.168.0.10 port 38298 
[ ID] Interval           Transfer     Bitrate 
[  5]   0.00-1.00   sec  5.72 MBytes  48.0 Mbits/sec                   
[  5]   1.00-2.00   sec  8.22 MBytes  68.9 Mbits/sec                   
[  5]   2.00-3.00   sec  7.27 MBytes  61.0 Mbits/sec                   
[  5]   3.00-4.00   sec  7.28 MBytes  61.1 Mbits/sec                   
[  5]   4.00-5.00   sec  8.61 MBytes  72.1 Mbits/sec                   
[  5]   5.00-6.00   sec  8.09 MBytes  67.9 Mbits/sec                   
[  5]   6.00-7.00   sec  8.16 MBytes  68.4 Mbits/sec                   
[  5]   7.00-8.00   sec  7.27 MBytes  61.0 Mbits/sec                   
[  5]   8.00-9.00   sec  7.32 MBytes  61.2 Mbits/sec                   
[  5]   9.00-10.00  sec  8.92 MBytes  75.0 Mbits/sec                   
[  5]  10.00-10.00  sec  31.1 KBytes  78.1 Mbits/sec                   
- - - - - - - - - - - - - - - - - - - - - - - - - 
[ ID] Interval           Transfer     Bitrate 
[  5]   0.00-10.00  sec  76.9 MBytes  64.5 Mbits/sec                  receiver 
----------------------------------------------------------- 
Server listening on 5201 
-----------------------------------------------------------

Вывод клиента

[root@Lhotze src]# iperf3 -c 192.168.0.3        
Connecting to host 192.168.0.3, port 5201 
[  5] local 192.168.0.10 port 38298 connected to 192.168.0.3 port 5201 
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd 
[  5]   0.00-1.00   sec  6.79 MBytes  56.9 Mbits/sec    0    267 KBytes        
[  5]   1.00-2.00   sec  9.64 MBytes  80.9 Mbits/sec    0    494 KBytes        
[  5]   2.00-3.00   sec  7.26 MBytes  60.9 Mbits/sec    0    494 KBytes        
[  5]   3.00-4.00   sec  6.90 MBytes  57.9 Mbits/sec    0    494 KBytes        
[  5]   4.00-5.00   sec  8.26 MBytes  69.3 Mbits/sec    0    494 KBytes        
[  5]   5.00-6.00   sec  9.13 MBytes  76.6 Mbits/sec    0    494 KBytes        
[  5]   6.00-7.00   sec  8.02 MBytes  67.2 Mbits/sec    0    494 KBytes        
[  5]   7.00-8.00   sec  6.96 MBytes  58.4 Mbits/sec    0    494 KBytes        
[  5]   8.00-9.00   sec  6.52 MBytes  54.7 Mbits/sec    0    494 KBytes        
[  5]   9.00-10.00  sec  9.26 MBytes  77.7 Mbits/sec    0    494 KBytes        
- - - - - - - - - - - - - - - - - - - - - - - - - 
[ ID] Interval           Transfer     Bitrate         Retr 
[  5]   0.00-10.00  sec  78.7 MBytes  66.1 Mbits/sec    0             sender 
[  5]   0.00-10.00  sec  76.9 MBytes  64.5 Mbits/sec                  receiver 

iperf Done.

При работе сетевого интерфейса на сервере HiFive со скоростью 100 Мбит/с средняя скорость обмена составила 64,5 Мбит/с или 64,5% от номинальной скорости более медленного интерфейса. Размер окна cwnd при этом в течение 9 из 10 интервалов измерения был постоянным (494 кбайта) и лишь в первом интервале составил 267 кбайт.

Устанавливаем на интерфейсе сервера HiFive скорость 10 Мбит/с и повторяем тест.

Вывод сервера

root@freedom-u540:~# ethtool -s eth0 speed 10 autoneg off 

root@freedom-u540:~# iperf3 -s                 
----------------------------------------------------------- 
Server listening on 5201 
----------------------------------------------------------- 
Accepted connection from 192.168.0.10, port 38330 
[  5] local 192.168.0.3 port 5201 connected to 192.168.0.10 port 38332 
[ ID] Interval           Transfer     Bitrate 
[  5]   0.00-1.00   sec   546 KBytes  4.47 Mbits/sec                   
[  5]   1.00-2.00   sec   785 KBytes  6.42 Mbits/sec                   
[  5]   2.00-3.00   sec   993 KBytes  8.13 Mbits/sec                   
[  5]   3.00-4.00   sec   998 KBytes  8.17 Mbits/sec                   
[  5]   4.00-5.00   sec   998 KBytes  8.18 Mbits/sec                   
[  5]   5.00-6.00   sec   993 KBytes  8.13 Mbits/sec                   
[  5]   6.00-7.00   sec  1001 KBytes  8.20 Mbits/sec                   
[  5]   7.00-8.00   sec   994 KBytes  8.14 Mbits/sec                   
[  5]   8.00-9.00   sec   996 KBytes  8.15 Mbits/sec                   
[  5]   9.00-10.00  sec  1003 KBytes  8.22 Mbits/sec                   
[  5]  10.00-10.01  sec  7.07 KBytes  7.71 Mbits/sec                   
- - - - - - - - - - - - - - - - - - - - - - - - - 
[ ID] Interval           Transfer     Bitrate 
[  5]   0.00-10.01  sec  9.09 MBytes  7.62 Mbits/sec                  receiver 
----------------------------------------------------------- 
Server listening on 5201 
-----------------------------------------------------------

Вывод клиента

[root@Lhotze src]# iperf3 -c 192.168.0.3 
Connecting to host 192.168.0.3, port 5201 
[  5] local 192.168.0.10 port 38332 connected to 192.168.0.3 port 5201 
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd 
[  5]   0.00-1.00   sec   730 KBytes  5.98 Mbits/sec    0   41.0 KBytes        
[  5]   1.00-2.00   sec   840 KBytes  6.88 Mbits/sec    0   65.0 KBytes        
[  5]   2.00-3.00   sec  1.09 MBytes  9.18 Mbits/sec    0   65.0 KBytes        
[  5]   3.00-4.00   sec   902 KBytes  7.39 Mbits/sec    0   65.0 KBytes        
[  5]   4.00-5.00   sec  1.09 MBytes  9.18 Mbits/sec    0   65.0 KBytes        
[  5]   5.00-6.00   sec   933 KBytes  7.65 Mbits/sec    0   65.0 KBytes        
[  5]   6.00-7.00   sec   933 KBytes  7.65 Mbits/sec    0   65.0 KBytes        
[  5]   7.00-8.00   sec   933 KBytes  7.65 Mbits/sec    0   65.0 KBytes        
[  5]   8.00-9.00   sec  1.09 MBytes  9.18 Mbits/sec    0   65.0 KBytes        
[  5]   9.00-10.00  sec   933 KBytes  7.64 Mbits/sec    0   65.0 KBytes        
- - - - - - - - - - - - - - - - - - - - - - - - - 
[ ID] Interval           Transfer     Bitrate         Retr 
[  5]   0.00-10.00  sec  9.34 MBytes  7.84 Mbits/sec    0             sender 
[  5]   0.00-10.01  sec  9.09 MBytes  7.62 Mbits/sec                  receiver 

iperf Done.

В этом случае скорость обмена составила 7,62 Мбит/с или 72,6% от номинальной скорости более медленного интерфейса. Окно насыщения во всех интервалах измерения кроме первого имело размер 65 кбайт, а в первом интервале — 41 кбайт.

Из приведенного выше вывода очевидно, что во всех вариантах теста скорость обмена по сети была существенно ниже номинальной скорости линии, определяемой более медленным интерфейсом. Особенно сильно это проявлялось при скорости 1000 Мбит/с.

Далее были выполнены измерения с помощью программы iperf на клиенте HiFive (сервером служила программа iperf3) на скорости интерфейса 10, 100 и 1000 Мбит/с с заданием в каждом случае максимальной скорости передачи клиента (опция -b) в соответствии с номинальной скоростью линии.

1000 Мбит/с

root@freedom-u540:~# iperf -p 5201 -b 1G -c 192.168.0.10    
------------------------------------------------------------ 
Client connecting to 192.168.0.10, TCP port 5201 
TCP window size: 85.0 KByte (default) 
------------------------------------------------------------ 
[  3] local 192.168.0.3 port 46780 connected with 192.168.0.10 port 5201 
[ ID] Interval       Transfer     Bandwidth 
[  3]  0.0-10.0 sec   222 MBytes   186 Mbits/sec

100 Мбит/с

root@freedom-u540:~# ethtool -s eth0 speed 100 autoneg off  
root@freedom-u540:~# iperf -p 5201 -b 100M -c 192.168.0.10    
------------------------------------------------------------ 
Client connecting to 192.168.0.10, TCP port 5201 
TCP window size: 85.0 KByte (default) 
------------------------------------------------------------ 
[  3] local 192.168.0.3 port 46782 connected with 192.168.0.10 port 5201 
[ ID] Interval       Transfer     Bandwidth 
[  3]  0.0-10.0 sec  52.4 MBytes  43.9 Mbits/sec

10 Мбит/с

root@freedom-u540:~# ethtool -s eth0 speed 10 autoneg off  
root@freedom-u540:~# iperf -p 5201 -b 10M -c 192.168.0.10 
------------------------------------------------------------ 
Client connecting to 192.168.0.10, TCP port 5201 
TCP window size: 85.0 KByte (default) 
------------------------------------------------------------ 
[  3] local 192.168.0.3 port 46786 connected with 192.168.0.10 port 5201 
[ ID] Interval       Transfer     Bandwidth 
[  3]  0.0-10.0 sec  9.00 MBytes  7.54 Mbits/sec

И снова, как в случае iperf3 измеренная скорость существенно ниже номинальной скорости линии, а относительная скорость растет при снижении скорости более медленного интерфейса

После этого была восстановлена скорость 1000 Мбит/с на интерфейсе хоста HiFive и менялась скорость интерфейса на сервере (100 и 10 Мбит/с), при этом клиенту iperf на хосте HiFive задавалась полная скорость (1000 Мбит/с)

Сервер 100 Мбит/с

------------------------------------------------------------ 
Client connecting to 192.168.0.10, TCP port 5201 
TCP window size:  102 KByte (default) 
------------------------------------------------------------ 
[  3] local 192.168.0.3 port 46788 connected with 192.168.0.10 port 5201 
[ ID] Interval       Transfer     Bandwidth 
[  3]  0.0-10.0 sec  42.5 MBytes  35.6 Mbits/sec

Сервер 10 Мбит/с

root@freedom-u540:~# iperf -p 5201 -b 1G -c 192.168.0.10 
------------------------------------------------------------ 
Client connecting to 192.168.0.10, TCP port 5201 
TCP window size: 85.0 KByte (default) 
------------------------------------------------------------ 
[  3] local 192.168.0.3 port 46790 connected with 192.168.0.10 port 5201 
[ ID] Interval       Transfer     Bandwidth 
[  3]  0.0-10.1 sec  4.50 MBytes  3.73 Mbits/sec

Скорость обмена через сеть в обоих случаях не достигала и 40% от номинальной скорости линии у клиента.

Зависимость от скорости передачи на стороне клиента

Далее была восстановлены принятые по умолчанию настройки обоих сетевых интерфейсов (полнодуплексный режим, 1000 Мбит/с) и менялась скорость передачи пакетов на уровне клиента HiFive. Напомним, что по умолчанию iperf3 для тестов TCP использует полную скорость линии.

Приводится вывод лишь клиентской стороны, поскольку он более информативен.

Скорость передачи на стороне клиента 1000 Мбит/с

root@freedom-u540:~# iperf3 -c 192.168.0.10 -b 1000M 
Connecting to host 192.168.0.10, port 5201 
[  5] local 192.168.0.3 port 56086 connected to 192.168.0.10 port 5201 
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd 
[  5]   0.00-1.00   sec  16.4 MBytes   137 Mbits/sec    0    158 KBytes        
[  5]   1.00-2.00   sec  16.4 MBytes   137 Mbits/sec    0    158 KBytes        
[  5]   2.00-3.01   sec  16.6 MBytes   139 Mbits/sec    0    158 KBytes        
[  5]   3.01-4.00   sec  16.2 MBytes   137 Mbits/sec    0    158 KBytes        
[  5]   4.00-5.00   sec  16.4 MBytes   137 Mbits/sec    0    167 KBytes        
[  5]   5.00-6.01   sec  16.5 MBytes   138 Mbits/sec    0    167 KBytes        
[  5]   6.01-7.00   sec  16.4 MBytes   138 Mbits/sec    0    167 KBytes        
[  5]   7.00-8.00   sec  16.5 MBytes   139 Mbits/sec    0    167 KBytes        
[  5]   8.00-9.00   sec  16.4 MBytes   137 Mbits/sec    0    167 KBytes        
[  5]   9.00-10.00  sec  16.5 MBytes   139 Mbits/sec    0    167 KBytes        
- - - - - - - - - - - - - - - - - - - - - - - - - 
[ ID] Interval           Transfer     Bitrate         Retr 
[  5]   0.00-10.00  sec   164 MBytes   138 Mbits/sec    0             sender 
[  5]   0.00-10.01  sec   164 MBytes   138 Mbits/sec                  receiver 

iperf Done. 

Постепенное снижение скорости передачи на клиенте от 1000 до 140 Мбит/с давало близкие результаты со средней скоростью обмена чуть меньше 140 Мбит/с. Однако при скорости передачи клиента меньше 140 Мбит/с средняя скорость обмена между клиентом уже совпадала со скоростью передачи.

Скорость передачи на стороне клиента 140 Мбит/с

root@freedom-u540:~# iperf3 -c 192.168.0.10 -b 140M  
Connecting to host 192.168.0.10, port 5201 
[  5] local 192.168.0.3 port 56110 connected to 192.168.0.10 port 5201 
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd 
[  5]   0.00-1.00   sec  16.5 MBytes   138 Mbits/sec    0    153 KBytes        
[  5]   1.00-2.00   sec  16.5 MBytes   138 Mbits/sec    0    168 KBytes        
[  5]   2.00-3.00   sec  16.4 MBytes   138 Mbits/sec    0    177 KBytes        
[  5]   3.00-4.01   sec  16.5 MBytes   138 Mbits/sec    0    177 KBytes        
[  5]   4.01-5.00   sec  16.2 MBytes   137 Mbits/sec    0    177 KBytes        
[  5]   5.00-6.00   sec  16.4 MBytes   137 Mbits/sec    0    177 KBytes        
[  5]   6.00-7.00   sec  16.4 MBytes   137 Mbits/sec    0    177 KBytes        
[  5]   7.00-8.01   sec  16.5 MBytes   138 Mbits/sec    0    177 KBytes        
[  5]   8.01-9.00   sec  16.1 MBytes   136 Mbits/sec    0    177 KBytes        
[  5]   9.00-10.01  sec  16.4 MBytes   137 Mbits/sec    0    177 KBytes        
- - - - - - - - - - - - - - - - - - - - - - - - - 
[ ID] Interval           Transfer     Bitrate         Retr 
[  5]   0.00-10.01  sec   164 MBytes   137 Mbits/sec    0             sender 
[  5]   0.00-10.01  sec   164 MBytes   137 Mbits/sec                  receiver 

iperf Done.

Скорость передачи на стороне клиента 130 Мбит/с

root@freedom-u540:~# iperf3 -c 192.168.0.10 -b 130M  
Connecting to host 192.168.0.10, port 5201 
[  5] local 192.168.0.3 port 56114 connected to 192.168.0.10 port 5201 
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd 
[  5]   0.00-1.00   sec  15.5 MBytes   130 Mbits/sec    0    158 KBytes        
[  5]   1.00-2.00   sec  15.5 MBytes   130 Mbits/sec    0    158 KBytes        
[  5]   2.00-3.00   sec  15.5 MBytes   130 Mbits/sec    0    158 KBytes        
[  5]   3.00-4.00   sec  15.5 MBytes   130 Mbits/sec    0    167 KBytes        
[  5]   4.00-5.00   sec  15.5 MBytes   130 Mbits/sec    0    167 KBytes        
[  5]   5.00-6.00   sec  15.5 MBytes   130 Mbits/sec    0    167 KBytes        
[  5]   6.00-7.00   sec  15.5 MBytes   130 Mbits/sec    0    167 KBytes        
[  5]   7.00-8.00   sec  15.5 MBytes   130 Mbits/sec    0    167 KBytes        
[  5]   8.00-9.00   sec  15.5 MBytes   130 Mbits/sec    0    167 KBytes        
[  5]   9.00-10.00  sec  15.5 MBytes   130 Mbits/sec    0    167 KBytes        
- - - - - - - - - - - - - - - - - - - - - - - - - 
[ ID] Interval           Transfer     Bitrate         Retr 
[  5]   0.00-10.00  sec   155 MBytes   130 Mbits/sec    0             sender 
[  5]   0.00-10.01  sec   155 MBytes   130 Mbits/sec                  receiver 

iperf Done.

Скорость передачи на стороне клиента 100 Мбит/с

root@freedom-u540:~# iperf3 -c 192.168.0.10 -b 100M 
Connecting to host 192.168.0.10, port 5201 
[  5] local 192.168.0.3 port 56126 connected to 192.168.0.10 port 5201 
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd 
[  5]   0.00-1.00   sec  12.0 MBytes   100 Mbits/sec    0    151 KBytes        
[  5]   1.00-2.00   sec  11.9 MBytes  99.9 Mbits/sec    0    151 KBytes        
[  5]   2.00-3.01   sec  12.0 MBytes   100 Mbits/sec    0    151 KBytes        
[  5]   3.01-4.00   sec  11.9 MBytes   100 Mbits/sec    0    151 KBytes        
[  5]   4.00-5.00   sec  11.9 MBytes  99.6 Mbits/sec    0    151 KBytes        
[  5]   5.00-6.01   sec  12.0 MBytes   100 Mbits/sec    0    151 KBytes        
[  5]   6.01-7.00   sec  11.9 MBytes   100 Mbits/sec    0    151 KBytes        
[  5]   7.00-8.01   sec  12.0 MBytes   100 Mbits/sec    0    151 KBytes        
[  5]   8.01-9.00   sec  11.9 MBytes  99.9 Mbits/sec    0    151 KBytes        
[  5]   9.00-10.00  sec  11.9 MBytes  99.7 Mbits/sec    0    151 KBytes        
- - - - - - - - - - - - - - - - - - - - - - - - - 
[ ID] Interval           Transfer     Bitrate         Retr 
[  5]   0.00-10.00  sec   119 MBytes   100 Mbits/sec    0             sender 
[  5]   0.00-10.01  sec   119 MBytes  99.9 Mbits/sec                  receiver 

iperf Done.

Скорость передачи на стороне клиента 50 Мбит/с

root@freedom-u540:~# iperf3 -c 192.168.0.10 -b 50M   
Connecting to host 192.168.0.10, port 5201 
[  5] local 192.168.0.3 port 56130 connected to 192.168.0.10 port 5201 
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd 
[  5]   0.00-1.00   sec  5.98 MBytes  50.1 Mbits/sec    0    130 KBytes        
[  5]   1.00-2.00   sec  6.00 MBytes  50.3 Mbits/sec    0    130 KBytes        
[  5]   2.00-3.00   sec  6.00 MBytes  50.2 Mbits/sec    0    130 KBytes        
[  5]   3.00-4.00   sec  5.88 MBytes  49.5 Mbits/sec    0    130 KBytes        
[  5]   4.00-5.00   sec  6.00 MBytes  50.3 Mbits/sec    0    130 KBytes        
[  5]   5.00-6.00   sec  6.00 MBytes  50.2 Mbits/sec    0    130 KBytes        
[  5]   6.00-7.00   sec  5.88 MBytes  49.4 Mbits/sec    0    130 KBytes        
[  5]   7.00-8.00   sec  6.00 MBytes  50.3 Mbits/sec    0    130 KBytes        
[  5]   8.00-9.01   sec  6.00 MBytes  50.1 Mbits/sec    0    130 KBytes        
[  5]   9.01-10.00  sec  5.88 MBytes  49.5 Mbits/sec    0    130 KBytes        
- - - - - - - - - - - - - - - - - - - - - - - - - 
[ ID] Interval           Transfer     Bitrate         Retr 
[  5]   0.00-10.00  sec  59.6 MBytes  50.0 Mbits/sec    0             sender 
[  5]   0.00-10.01  sec  59.6 MBytes  50.0 Mbits/sec                  receiver 

iperf Done.

Скорость передачи на стороне клиента 10 Мбит/с

root@freedom-u540:~# iperf3 -c 192.168.0.10 -b 10M  
Connecting to host 192.168.0.10, port 5201 
[  5] local 192.168.0.3 port 56134 connected to 192.168.0.10 port 5201 
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd 
[  5]   0.00-1.00   sec  1.25 MBytes  10.5 Mbits/sec    0   72.1 KBytes        
[  5]   1.00-2.00   sec  1.25 MBytes  10.5 Mbits/sec    0    123 KBytes        
[  5]   2.00-3.00   sec  1.12 MBytes  9.44 Mbits/sec    0    130 KBytes        
[  5]   3.00-4.00   sec  1.25 MBytes  10.5 Mbits/sec    0    130 KBytes        
[  5]   4.00-5.00   sec  1.12 MBytes  9.44 Mbits/sec    0    130 KBytes        
[  5]   5.00-6.00   sec  1.25 MBytes  10.5 Mbits/sec    0    130 KBytes        
[  5]   6.00-7.00   sec  1.12 MBytes  9.44 Mbits/sec    0    130 KBytes        
[  5]   7.00-8.00   sec  1.25 MBytes  10.5 Mbits/sec    0    130 KBytes        
[  5]   8.00-9.00   sec  1.12 MBytes  9.44 Mbits/sec    0    130 KBytes        
[  5]   9.00-10.00  sec  1.25 MBytes  10.5 Mbits/sec    0    130 KBytes        
- - - - - - - - - - - - - - - - - - - - - - - - - 
[ ID] Interval           Transfer     Bitrate         Retr 
[  5]   0.00-10.00  sec  12.0 MBytes  10.1 Mbits/sec    0             sender 
[  5]   0.00-10.01  sec  12.0 MBytes  10.1 Mbits/sec                  receiver 

iperf Done.

Аналогичные тесты в обратном направлении дали похожий результат. При скоростях от 1000 Мбит/с до средней скорости, которая обеспечивалась при отсутствии ограничений, скорость сетевого обмена практически не менялась и была ниже скорости передачи, установленной для клиента, а после достижения этого порога скорость обмена между клиентом и сервером в точности совпадала со скоростью передачи, заданной на клиентской стороне.

Это позволяет с уверенностью считать, что результаты измерения скорости обмена по протоколу TCP определяются прежде всего параметрами TCP, а не физическими параметрами интерфейсов хостов и производительностью процессоров. Асимметрия скорости (при смене ролей клиента и сервера) объясняется разными настройками протокола TCP на двух хостах.

Дополнительные измерения

Заключительным был эксперимент по измерению скорости с помощью iperf3 через Internet, когда между сервером и клиентом присутствовало неопределенное число маршрутизаторов. На сервере пропускная способность ограничена значением 100 Мбит/с.

Вывод клиента

root@freedom-u540:~# iperf3 -c protokols.ru 
Connecting to host nmalykh.org, port 5201 
[  5] local 192.168.0.3 port 44460 connected to 185.147.80.144 port 5201 
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd 
[  5]   0.00-1.00   sec  12.6 MBytes   106 Mbits/sec   45    355 KBytes        
[  5]   1.00-2.01   sec  11.5 MBytes  95.6 Mbits/sec    0    412 KBytes        
[  5]   2.01-3.00   sec  10.8 MBytes  91.2 Mbits/sec    5    320 KBytes        
[  5]   3.00-4.00   sec  11.4 MBytes  95.8 Mbits/sec    0    345 KBytes        
[  5]   4.00-5.00   sec  11.8 MBytes  98.9 Mbits/sec    0    362 KBytes        
[  5]   5.00-6.00   sec  10.9 MBytes  91.7 Mbits/sec    0    384 KBytes        
[  5]   6.00-7.00   sec  11.5 MBytes  96.3 Mbits/sec    0    406 KBytes        
[  5]   7.00-8.00   sec  11.5 MBytes  96.3 Mbits/sec    0    427 KBytes        
[  5]   8.00-9.00   sec  11.1 MBytes  93.2 Mbits/sec    8    342 KBytes        
[  5]   9.00-10.00  sec  11.5 MBytes  96.9 Mbits/sec    0    384 KBytes        
- - - - - - - - - - - - - - - - - - - - - - - - - 
[ ID] Interval           Transfer     Bitrate         Retr 
[  5]   0.00-10.00  sec   115 MBytes  96.2 Mbits/sec   58             sender 
[  5]   0.00-10.00  sec   114 MBytes  95.3 Mbits/sec                  receiver 

iperf Done.

Вывод сервера

[root@nmalykh nmalykh]# iperf3 -s 
----------------------------------------------------------- 
Server listening on 5201 
----------------------------------------------------------- 
Accepted connection from 91.122.87.84, port 44458 
[  5] local 185.147.80.144 port 5201 connected to 91.122.87.84 port 44460 
[ ID] Interval           Transfer     Bandwidth 
[  5]   0.00-1.00   sec  11.1 MBytes  93.0 Mbits/sec                   
[  5]   1.00-2.00   sec  11.4 MBytes  95.4 Mbits/sec                   
[  5]   2.00-3.00   sec  11.4 MBytes  95.4 Mbits/sec                   
[  5]   3.00-4.00   sec  11.4 MBytes  95.4 Mbits/sec                   
[  5]   4.00-5.00   sec  11.4 MBytes  95.4 Mbits/sec                   
[  5]   5.00-6.00   sec  11.4 MBytes  95.4 Mbits/sec                   
[  5]   6.00-7.00   sec  11.4 MBytes  95.4 Mbits/sec                   
[  5]   7.00-8.00   sec  11.4 MBytes  95.4 Mbits/sec                   
[  5]   8.00-9.00   sec  11.4 MBytes  95.4 Mbits/sec                   
[  5]   9.00-10.00  sec  11.4 MBytes  95.4 Mbits/sec                   
[  5]  10.00-10.01  sec   142 KBytes  94.3 Mbits/sec                   
- - - - - - - - - - - - - - - - - - - - - - - - - 
[ ID] Interval           Transfer     Bandwidth 
[  5]   0.00-10.01  sec  0.00 Bytes  0.00 bits/sec                  sender 
[  5]   0.00-10.01  sec   114 MBytes  95.2 Mbits/sec                  receiver 
----------------------------------------------------------- 
Server listening on 5201 
-----------------------------------------------------------

Здесь скорость обмена практически явно ограничивалась на уровнях 3 и 4 модели OSI (механизм ограничения пропускной способности на хосте protokols.ru точно не известен), поэтому скорость обмена фактически совпадала с номинальной скоростью линии.

Для сравнения ниже представлен результат измерения скорости обмена между двумя хостами с одной операционной системой (Mageia 7.1) в той же ЛВС. На обоих хостах сетевые интерфейсы использовали принятые по умолчанию параметры. Результаты измерений в том и другом направлении практически не отличались, поэтому приведен лишь вывод на стороне клиента для одного из направлений.

[root@Lhotze ~]# iperf3 -c 192.168.0.6 
Connecting to host 192.168.0.6, port 5201 
[  5] local 192.168.0.10 port 54170 connected to 192.168.0.6 port 5201 
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd 
[  5]   0.00-1.00   sec   107 MBytes   895 Mbits/sec    0    696 KBytes        
[  5]   1.00-2.00   sec   104 MBytes   870 Mbits/sec    0    769 KBytes        
[  5]   2.00-3.00   sec   105 MBytes   881 Mbits/sec    0    850 KBytes        
[  5]   3.00-4.00   sec   104 MBytes   870 Mbits/sec    0    935 KBytes        
[  5]   4.00-5.00   sec   104 MBytes   870 Mbits/sec    0    984 KBytes        
[  5]   5.00-6.00   sec   104 MBytes   870 Mbits/sec    0    984 KBytes        
[  5]   6.00-7.00   sec   104 MBytes   870 Mbits/sec    0   1.01 MBytes        
[  5]   7.00-8.00   sec   104 MBytes   870 Mbits/sec    0   1.01 MBytes        
[  5]   8.00-9.00   sec   104 MBytes   870 Mbits/sec    0   1.01 MBytes        
[  5]   9.00-10.00  sec   104 MBytes   870 Mbits/sec    0   1.01 MBytes        
- - - - - - - - - - - - - - - - - - - - - - - - - 
[ ID] Interval           Transfer     Bitrate         Retr 
[  5]   0.00-10.00  sec  1.02 GBytes   874 Mbits/sec    0             sender 
[  5]   0.00-10.00  sec  1.01 GBytes   872 Mbits/sec                  receiver 

iperf Done.

Заключение

Приведенные результаты позволяют с достаточной уверенностью считать, что измерения с помощью утилиты iperf3 при использовании принятого по умолчанию протокола TCP отражают не столько возможности и параметры физического интерфейса и драйвера, сколько параметры управления потоком данных протокола TCP. Поскольку мы пытаемся разобраться с возможностями и ограничениями процессоров Freedom U540 и сетевой подсистемы платы HiFive Unleashed, важнее разобраться с уровнями 1 — 2 эталонной модели OSI без влияния настроек вышележащих уровней. Для оценки реализации нижних уровней сетевого стека TCP/IP измерения, на которые определяющее влияние оказывает управление потоком данных на транспортном уровне, практической ценности не представляют, поэтому далее мы перейдем к измерениям на основе протокола UDP, поскольку в этом случае влияние верхних уровней стека протоколов существенно меньше.

Рубрика: Linux, RISC-V, Измерения и тестирование | Комментарии к записи Тестирование платы HiFive Unleashed с ядром Linux 5.2.9 отключены

Руководство для разработчиков Yocto Project Linux Kernel

Руководство для разработчиков Yocto Project Linux Kernel

PDF

Scott Rifenbark

Scotty’s Documentation Services, INC

<srifenbark@gmail.com>

Copyright © 2010-2019 Linux Foundation

Разрешается копирование, распространение и изменение документа на условиях лицензии Creative Commons Attribution-Share Alike 2.0 UK: England & Wales, опубликованной Creative Commons.

Глава 1. Введение

1.1. Обзор

Независимо от целей использования Yocto Project (YP), велика вероятность работы с ядром Linux. В этом документе описано как организовать сборочный хост для поддержки работы с ядром, приведена вводная информация о процессах разработки ядра, а также базовые сведения о метаданных ядра (Metadata), описывающих задачи, доступные с помощью инструментов ядра и применение Metadata для работы с ядром в YP, а также рассмотрены вопросы разработки поддержки командой YP репозиториев Git и Metadata для ядра.

Каждый выпуск YP имеет набор заданий (recipe) Yocto Linux kernel, Git-репозитории которых можно увидеть в Yocto Source Repositories [3] под заголовком Yocto Linux Kernel. Новые задания для выпусков отслеживают разработки ядра Linux с сайта http://www.kernel.org и добавляют поддержку новых платформ. Прежние задания в выпуске обновляются и поддерживаются по меньшей мере до следующего выпуска YP. По мере внесения изменений эти выпуски обновляются и включают все новое из проекта LTSI1. Дополнительная информация о ядрах Yocto Linux и LTSI приведена в приложении A.1. Разработка и поддержка YP Kernel.

В проект включено задание для работы с ядром linux-yocto-dev.bb, которое позволяет ознакомится с находящимися в разработке ядром Yocto Linux и Metadata.

YP также включает мощный набор инструментов ядра для управления исходными кодами Yocto Linux и параметрами конфигурации. Эти инструменты могут служить для внесения единичных изменений, применения множества исправлений (patch) или разработки своих компонент ядра.

В частности, эти инструменты позволяют генерировать фрагменты конфигурации, которые задают лишь то, что нужно сделать, не затрагивая остального. Во фрагменты конфигурации требуется включать лишь видимые опции верхнего уровня, представляемые системой Yocto Linux menuconfig. В отличие от этого полный файл Yocto Linux .config включает все автоматически выбираемые опции CONFIG. Это снижает объем работы по поддержке и позволяет дополнительно разделить конфигурацию удобным для вашего проекта способом. Обычно разделяются компоненты, связанные с оборудованием и правилами. Например, ваше ядро может поддерживать файловые системы proc и sys, а поддержка звука, USB и некоторых драйверов нужна лишь для отдельных плат. Задавая эти параметры отдельно, вы потом можете собрать их воедино, но поддерживать каждый фрагмент независимо. Аналогичная логика применима и для разделения вносимых в код изменений.

Если вы не поддерживаете своего дерева исходных кодов ядра и нужны лишь незначительные изменения в исходных файлах, выпущенные задания обеспечивают надежный способ наложить ваши правки. Это позволяет вам сохранить интеграцию ядра с тестированием производительности в процессе работы с YP.

Если же у вас имеется свое дерево исходных кодов ядра Linux и вы не можете совместить его ни с одним из официальных Yocto Linux kernel recipe, можно использовать инструменты ядра YP Linux с вашими исходными кодами.

Далее приведены инструкции по решению конкретных задач при работе с ядром Linux. Эти инструкции предполагают знакомство читателя с заданиями BitBake и основными инструментами для разработки систем с открытым кодом. Эти знания облегчат понимание процессов работы с заданиями для ядра (kernel recipe). Дополнительную информацию можно найти по ссылкам, приведенным в конце документа.

1.2. Рабочий процесс изменения ядра

Изменение ядра включает изменения в YP, которые могут включать смену параметров конфигурации, а также добавление в ядро новых заданий. Конфигурационные изменения могут быть добавлены в форме фрагментов конфигурации, а изменения заданий будут проходить через область recipes-kernel на созданном вами уровне.

В этом параграфе представлен общий обзор процесса изменения ядра в YP. На рисунке и в следующем за ним списке представлена базовая информация и ссылки на дополнительные источники.

  1. Организация на хосте среды разработки с использованием YPв разделе Setting Up the Development Host to Use the Yocto Project [4] описаны варианты организации сборочного хоста YP.

  2. Организация системы разработки для работы с ядром. Рекомендуется использовать devtool и расширяемый SDK2 (eSDK). Другим вариантом является использование традиционных методов разработки ядра в среде YP. Для обоих вариантов приведены этапы организации среды разработки.

    Для использования devtool и eSDK нужна «чистая» сборка образа и установка подходящего eSDK (см. параграф 2.1.1. Подготовка к работе с использованием devtool).

    Для использования традиционных методов нужны исходные коды ядра в виде изолированного от среды разработки локального репозитория Git (см. параграф 2.1.2. Подготовка к традиционной работе с ядром).

  3. Внесение изменений в исходный код ядра (при необходимости). Изменение ядра не всегда требует вмешательства в файлы исходного кода. Однако при необходимости можно внести изменения в файлы каталога сборки eSDK, если используется devtool (см. параграф 2.4. Использование devtool для применения изменений к ядру).

    При использовании традиционных методов редактируются файлы в локальном репозитории Git (см. параграф 2.5. Традиционные методы внесения изменений в ядро).

  4. Изменение конфигурации ядра (при необходимости). Если вам нужно изменить конфигурацию ядра, можно воспользоваться командой menuconfig (2.6.1. Использование menuconfig), которая позволяет в интерактивном режиме изменить и проверить конфигурацию ядра. При сохранении результатов menuconfig обновляет файл .config.

    Старайтесь не редактировать файл .config в каталоге сборки напрямую, поскольку это может приводить к непредсказуемым результатам, когда система сборки OpenEmbedded (OE) регенерирует конфигурационный файл.

    После создания нужной конфигурации с помощью menuconfig и сохранения файла можно напрямую сравнить полученный файл .config с имеющимся вариантом конфигурации и собрать изменения в файл фрагмента конфигурации (2.6.3. Создание фрагментов конфигурации), указываемый в файле .bbappend для ядра.

    При работе с уровнем BSP3 и необходимости изменить конфигурацию ядра в BSP также можно использовать menuconfig.

  5. Сборка ядра с учетом изменений. Процесс сборки зависит от целевоей платформы (реальная плата или QEMU).

Далее в документе рассматриваются типовые процедуры работы с ядром, использование метаданных и концепции поддержки ядра Yocto Linux.

Глава 2. Базовые задачи

В этой главе описано несколько базовых задач, которые выполняются при работе с ядрами YP Linux. Эти задачи включают подготовку хоста для работы, подготовку уровня (layer), изменение имеющихся заданий, наложение «заплаток» (patch) для ядра, настройку конфигурации ядра, работу с вашими файлами исходного кода и встраивание внешних модулей.

Представленные здесь примеры подходят для YP 2.4 и последующих выпусков.

2.1. Подготовка сборочного хоста для работы с ядром

Перед началом работы с ядрами нужно подготовить ваш хост для использования YP. Информация по этому вопросу представлена в разделе Preparing the Build Host [4]. Частью подготовки системы является создание локального репозитория Source Directory(poky) [1] на вашей системе. Этот процесс подробно описан в разделе Cloning the poky Repository[4].

Выберите подходящую ветвь разработки или создайте свою локальную ветвь, указав определенный тег для получения нужной версии YP. Дополнительная информация по этим вопросам представлена в разделах Checking Out by Branch in Poky и Checking Out by Tag in Poky [4].

Для работы с ядрами лучше всего подходит инструмент (команда) devtool, а не традиционные методы работы с ядрами. В последующих параграфах рассматриваются оба подхода.

2.1.1. Подготовка к работе с использованием devtool

Ниже описаны подготовительные операции для обновления образа ядра с помощью devtool. По завершении процедуры вы получите «чистый» образ ядра и будете готовы к внесению изменений, описанных в параграфе 2.4. Использование devtool для применения изменений к ядру.

  1. Инициализация среды BitBake. Перед созданием расширяемого SDK нужно инициализировать среду сборки BitBake с помощью соответствующего сценария (например, oe-init-build-env).

         $ cd ~/poky
         $ source oe-init-build-env

    Приведенные команды предполагают, что репозитории исходных кодов (например, poky) были клонированы с помощью Git в локальный каталог poky в домашнем каталоге пользователя.

  2. Подготовка файла local.conf. По умолчанию для переменной MACHINE установлено значение qemux86, предполагающее сборку для эмулятора QEMU в 32-битовом режиме. Если нужен другой вариант, следует указать корректное значение переменной MACHINE в файле conf/local.conf file локального каталога сборки (~/poky/build в этом примере).

    Нужно также установить значение переменной MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS для включения модулей ядра. В примере используется принятое по умолчанию значение qemux86 переменной MACHINE, но нужно добавить в файл строку

         MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS += "kernel-modules"
  3. Создание уровня для исправлений (patch). Нужно создать уровень для размещения «заплаток» к образу ядра. Для этого служит команда bitbake-layers create-layer, как показано ниже.
         $ cd ~/poky/build
         $ bitbake-layers create-layer ../../meta-mylayer
         NOTE: Starting bitbake server...
         Add your new layer with 'bitbake-layers add-layer ../../meta-mylayer'
         $

    Базовые сведения о работе с общими уровнями и уровнями BSP приведены в разделе Understanding and Creating Layers [4] и разделе BSP Layers [5]. Использование команды bitbake-layers create-layer для быстрого создания уровня описано в разделе Creating a General Layer Using the bitbake-layers Script [4].

  4. Добавление в среду разработки BitBake информации о новом уровне. Как будет указано при создании уровня, нужно добавить его в переменную BBLAYERS в файле bblayers.conf, как показано ниже.

         $ cd ~/poky/build
         $ bitbake-layers add-layer ../../meta-mylayer
         NOTE: Starting bitbake server...
         $
  5. Сборка расширяемого SDK. С помощью BitBake создается расширяемый SDK для использования с образами, предназначенными для QEMU.

         $ cd ~/poky/build
         $ bitbake core-image-minimal -c populate_sdk_ext

    После завершения сборки файл установки SDK (.sh) будет размещаться в каталоге ~/poky/build/tmp/deploy/sdk. В этом примере файл установки называется poky-glibc-x86_64-core-image-minimal-i586-toolchain-ext-2.7.1.sh.

  6. Установка ESDK. Используйте указанную выше команду для установки SDK. Например, для установки в принятом по умолчанию каталоге ~/poky_sdk следует ввыести команды, показанные ниже.

    $ cd ~/poky/build/tmp/deploy/sdk
    $ ./poky-glibc-x86_64-core-image-minimal-i586-toolchain-ext-2.7.1.sh
    Poky (Yocto Project Reference Distro) Extensible SDK installer version 2.7.1
    ============================================================================
    Enter target directory for SDK (default: ~/poky_sdk):
    You are about to install the SDK to "/home/scottrif/poky_sdk". Proceed [Y/n]? Y
    Extracting SDK......................................done
    Setting it up...
    Extracting buildtools...
    Preparing build system...
    Parsing recipes: 100% |#################################################################| Time: 0:00:52
    Initializing tasks: 100% |############## ###############################################| Time: 0:00:04
    Checking sstate mirror object availability: 100% |######################################| Time: 0:00:00
    Parsing recipes: 100% |#################################################################| Time: 0:00:33
    Initializing tasks: 100% |##############################################################| Time: 0:00:00
    done

    Это говорит об успешной установке и готовности SDK к использованию.

    Каждый раз перед началом использования SDK в новой сессии нужно использовать сценарий настройки окружения, например

       $ . /home/scottrif/poky_sdk/environment-setup-i586-poky-linux
  7. Новая терминальная сессия для работы с ESDK. Для работы с SDK нужно установить новый терминал. Нельзя применять командный процессор BitBake для сборки инсталятора. После открытия новой терминальной сессии нужно запустить сценарий настройки среды SDK, как было указано при завершении установки SDK.

    $ source ~/poky_sdk/environment-setup-i586-poky-linux
    "SDK environment now set up; additionally you may now run devtool to perform development tasks.
    Run devtool --help for further details.

    Вывод предупреждения о попытке использовать общую среду для SDK и BitBake говорит о том, что вы не организовали другую сессию.

  8. Сборка чистого образа. Финальным этапом подготовки к работе с ядром является создание исходного образа с использованием devtool в новой терминальной сессии, где установлен и инициализирован SDK.

    $ devtool build-image
    Parsing recipes: 100% |##########################################| Time: 0:00:05
    Parsing of 830 .bb files complete (0 cached, 830 parsed). 1299 targets, 47 skipped, 0 masked, 0 errors.
    WARNING: No packages to add, building image core-image-minimal unmodified
    Loading cache: 100% |############################################| Time: 0:00:00
    Loaded 1299 entries from dependency cache.
    NOTE: Resolving any missing task queue dependencies
    Initializing tasks: 100% |#######################################| Time: 0:00:07
    Checking sstate mirror object availability: 100% |###############| Time: 0:00:00
    NOTE: Executing SetScene Tasks
    NOTE: Executing RunQueue Tasks
    NOTE: Tasks Summary: Attempted 2866 tasks of which 2604 didn't need to be rerun and all succeeded.
    NOTE: Successfully built core-image-minimal. You can find output files in /home/scottrif/poky_sdk/tmp/deploy/images/qemux86

    Если сборка выполняется для реального оборудования, а не эмулятора, вам потребуется переписать образ на карту памяти, которая будет устанавливаться в устройство. Пример для платы Minnowboard приведен на странице TipsAndTricks/KernelDevelopmentWithEsdk.

С этого момента вы можете начать работу с внесением изменений в ядро с помощью SDK. Наложение «заплаток» на ядро описано в разделе 2.4. Использование devtool для применения изменений к ядру.

2.1.2. Подготовка к традиционной работе с ядром

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

Выполните перечисленные ниже операции для обновления образа ядра с использованием традиционных методов в YP. По завершении процедуры вы будете готовы внести изменения в ядро, как описано в параграфе 2.5. Традиционные методы внесения изменений в ядро.

  1. Инициализация среды BitBake. Перед началом работы нужно инициализировать среду сборки BitBake с помощью соответствующего сценария (например, oe-init-build-env). В этом примере также нужно убедиться что в качестве локальной ветви для poky выбрана Yocto Project Warrior. Если это не так, перейдите (checkout) на ветвь , как описано в параграфе Checking out by Branch in Poky [4].

         $ cd ~/poky
         $ git branch
         master
         * Warrior
         $ source oe-init-build-env

    В приведенных выше командах предполагается, что каталог Source Repositories (poky) был клонирован с помощью Git в локальный репозиторий с именем poky.

  2. Подготовка файла local.conf. По умолчанию для переменной MACHINE установлено значение qemux86, предполагающее сборку для эмулятора QEMU в 32-битовом режиме. Если нужен другой вариант, следует указать корректное значение переменной MACHINE в файле conf/local.conf file локального каталога сборки (~/poky/build в этом примере).

    Нужно также установить значение переменной MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS для включения модулей ядра. В примере используется принятое по умолчанию значение qemux86 переменной MACHINE, но нужно добавить в файл строку

         MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS += "kernel-modules"
  3. Создание уровня для исправлений (patch). Нужно создать уровень для размещения «заплаток» к образу ядра. Для этого служит команда bitbake-layers create-layer, как показано ниже.

         $ cd ~/poky/build
         $ bitbake-layers create-layer ../../meta-mylayer
         NOTE: Starting bitbake server...
         Add your new layer with 'bitbake-layers add-layer ../../meta-mylayer'
         $

    Базовые сведения о работе с общими уровнями и уровнями BSP4 приведены в разделе Understanding and Creating Layers [4] и разделе BSP Layers [5]. Использование команды bitbake-layers create-layer для быстрого создания уровня описано в разделе Creating a General Layer Using the bitbake-layers Script [4].

  4. Информировать среду разработки BitBake о новом уровне. Нужно добавить переменную BBLAYERS в файл bblayers.conf, как показано ниже.

         $ cd ~/poky/build
         $ bitbake-layers add-layer ../../meta-mylayer
         NOTE: Starting bitbake server ...
         $
  5. Создание локальной копии репозитория Kernel Git. Вы можете найти репозитории Git для поддерживаемых в YP ядер в разделе Yocto Linux Kernel по ссылке http://git.yoctoproject.org.

    Для простоты рекомендуется создавать копию репозитория ядра за пределами каталога исходных кодов, который обычно именуется poky. Убедитесь также в выборе ветви standard/base. Ниже приведены команды для создания локальной копии ядра linux-yocto-4.12 из ветви standard/base. Ядро linux-yocto-4.12 можно использовать с YP версии 2.4 и выше.

         $ cd ~
         $ git clone git://git.yoctoproject.org/linux-yocto-4.12 --branch standard/base
         Cloning into 'linux-yocto-4.12'...
         remote: Counting objects: 6097195, done.
         remote: Compressing objects: 100% (901026/901026), done.
         remote: Total 6097195 (delta 5152604), reused 6096847 (delta 5152256)
         Receiving objects: 100% (6097195/6097195), 1.24 GiB | 7.81 MiB/s, done.
         Resolving deltas: 100% (5152604/5152604), done.
         Checking connectivity... done.
         Checking out files: 100% (59846/59846), done.
  6. Создание локальной копии репозитория Kernel Cache Git. Для простоты рекомендуется создавать копию репозитория ядра за пределами каталога исходных кодов, который обычно именуется poky. Убедитесь также в выборе ветви yocto-4.12. Ниже приведены команды для создания локальной копии yocto-kernel-cache (ветвь yocto-4.12).

         $ cd ~
         $ git clone git://git.yoctoproject.org/yocto-kernel-cache --branch yocto-4.12
         Cloning into 'yocto-kernel-cache'...
         remote: Counting objects: 22639, done.
         remote: Compressing objects: 100% (9761/9761), done.
         remote: Total 22639 (delta 12400), reused 22586 (delta 12347)
         Receiving objects: 100% (22639/22639), 22.34 MiB | 6.27 MiB/s, done.
         Resolving deltas: 100% (12400/12400), done.
         Checking connectivity... done.

С этого момента вы можете начать работу с внесением изменений в ядро с помощью традиционных средств. Наложение «заплаток» на ядро описано в разделе 2.5. Традиционные методы внесения изменений в ядро.

2.2. Создание и подготовка уровня

Если вы планируете менять задания (recipe) для ядра, рекомендуется создать и подготовить свой уровень, с которым вы будете работать. Этот уровень будет включать свой файл дополнения BitBake (.bbappend) и обеспечивать удобный механизм для создания файлов заданий (.bb), а также для хранения и применения «заплаток» к ядру. Работа с уровнями описана в разделе Understanding and Creating Layers [4].

YP включает множество инструментов для упрощения работы. Одним из таких инструментов является команда bitbake-layers create-layer (см. раздел Creating a General Layer Using the bitbake-layers Script [4]).

Для лучшего понимания роли создаваемого уровня при работе с ядром далее описано создание уровня без использования этих инструментов. Описанные этапы предполагают создание уровня mylayer в домашнем каталоге.

  1. Создание структуры уровня

         $ cd $HOME
         $ mkdir meta-mylayer
         $ mkdir meta-mylayer/conf
         $ mkdir meta-mylayer/recipes-kernel
         $ mkdir meta-mylayer/recipes-kernel/linux
         $ mkdir meta-mylayer/recipes-kernel/linux/linux-yocto

    Каталог содержит конфигурационные файлы, а recipes-kernelфайл и файлы исправлений (patch).

  2. Создание файла конфигурации уровня. Перейдите в каталог meta-mylayer/conf и создайте файл layer.conf, как показано ниже.

         # We have a conf and classes directory, add to BBPATH
         BBPATH .= ":${LAYERDIR}"
    
         # We have recipes-* directories, add to BBFILES
         BBFILES += "${LAYERDIR}/recipes-*/*/*.bb ${LAYERDIR}/recipes-*/*/*.bbappend"
    
         BBFILE_COLLECTIONS += "mylayer"
         BBFILE_PATTERN_mylayer = "^${LAYERDIR}/"
         BBFILE_PRIORITY_mylayer = "5"

    Обратите внимание на mylayer в трех последних строках.

  3. Создание файла добавления заданий. Перейдите в каталог meta-mylayer/recipes-kernel/linux и создайте файл добавления для ядра. В приведенном примере используется ядро linux-yocto-4.12. Поэтому файл добавления будет иметь имя linux-yocto_4.12.bbappend:

    FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
    
         SRC_URI_append += "file://patch-file-one" SRC_URI_append += "file://patch-file-two" SRC_URI_append += "file://patch-file-three"

    Операторы FILESEXTRAPATHS и SRC_URI позволяют системе сборки OE найти файлы добавления. Дополнительная информация об этих файлах приведена в разделе Using .bbappend Files in Your Layer [4].

2.3. Изменение существующего задания

Во многих случаях можно изменить имеющееся задание linux-yocto в соответствии с вашими требованиями. Каждый выпуск YP включает новые задания для ядра Linux, из которых можно выбирать. Эти задания размещаются в ветви meta/recipes-kernel/linux каталога исходных кодов.

Изменение имеющегося задания может включать:

  • создание файла добавления;

  • применение исправлений;

  • изменение конфигурации.

Перед внесением изменений в имеющееся задание создайте простой уровень, из которого вы сможете работать (см. 2.2. Создание и подготовка уровня).

2.3.1. Создание файла добавления

Этот файл вы создаете на своем уровне и называете его на основе используемого задания linux-yocto. Например, при изменении задания meta/recipes-kernel/linux/linux-yocto_4.12.bb файл добавления обычно будет размещаться на вашем уровне с именем

your-layer/recipes-kernel/linux/linux-yocto_4.12.bbappend

Файлу добавления сначала следует расширить путь поиска FILESPATH путем добавления в переменную FILESEXTRAPATHS каталогов, где размещаются ваши файлы, как показано ниже

     FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"

В примере путь ${THISDIR}/${PN} преобразуется в каталог linux-yocto в текущем каталоге. При добавлении новых файлов, которые меняют задания для ядра, и наличии преобразованного, как указано выше, пути, эти файлы нужно размещать в каталоге

your-layer/recipes-kernel/linux/linux-yocto/

Для работы с BSP для новой системы следует ознакомиться с документом [5].

В качестве примера рассмотрим файл, используемый BSP в составе уровня meta-yocto-bsp meta-yocto-bsp/recipes-kernel/linux/linux-yocto_4.12.bbappend. Содержимое этого файла приведено ниже. Отметим, что реальные идентификаторы представления могут быть иными в вашем уровне meta-yocto-bsp.

     KBRANCH_genericx86  = "standard/base"
     KBRANCH_genericx86-64  = "standard/base"

     KMACHINE_genericx86 ?= "common-pc"
     KMACHINE_genericx86-64 ?= "common-pc-64"
     KBRANCH_edgerouter = "standard/edgerouter"
     KBRANCH_beaglebone = "standard/beaglebone"
     KBRANCH_mpc8315e-rdb = "standard/fsl-mpc8315e-rdb"

     SRCREV_machine_genericx86    ?= "d09f2ce584d60ecb7890550c22a80c48b83c2e19"
     SRCREV_machine_genericx86-64 ?= "d09f2ce584d60ecb7890550c22a80c48b83c2e19"
     SRCREV_machine_edgerouter ?= "b5c8cfda2dfe296410d51e131289fb09c69e1e7d"
     SRCREV_machine_beaglebone ?= "b5c8cfda2dfe296410d51e131289fb09c69e1e7d"
     SRCREV_machine_mpc8315e-rdb ?= "2d1d010240846d7bff15d1fcc0cb6eb8a22fc78a"

     COMPATIBLE_MACHINE_genericx86 = "genericx86"
     COMPATIBLE_MACHINE_genericx86-64 = "genericx86-64"
     COMPATIBLE_MACHINE_edgerouter = "edgerouter"
     COMPATIBLE_MACHINE_beaglebone = "beaglebone"
     COMPATIBLE_MACHINE_mpc8315e-rdb = "mpc8315e-rdb"

     LINUX_VERSION_genericx86 = "4.12.7"
     LINUX_VERSION_genericx86-64 = "4.12.7"
     LINUX_VERSION_edgerouter = "4.12.10"
     LINUX_VERSION_beaglebone = "4.12.10"
     LINUX_VERSION_mpc8315e-rdb = "4.12.10"

Этот файл добавления служит для поддержки нескольких BSP из комплекта YP. Файл указывает машины в переменных COMPATIBLE_MACHINE, а для отображения имени машины на имя, используемое системой OE при сборке ядра Linux Yocto, указывает переменная переменная KMACHINE. Необязательные переменные KBRANCH задают используемую при сборке ветвь ядра.

В приведенном примере переменная KERNEL_FEATURES не используется, но она позволяет включить функции для конкретного ядра. Файл добавления указывает конкретные фиксации (commit) в репозитории Source Directory Git и ветвях репозитория метаданных для точного указания ядра, нужного для сборки BSP.

В рассматриваемом BSP отсутствует один элемент, который обычно требуется при разработке BSP, — файл конфигурации ядра (.config) для BSP. При создании BSP у вас скорей всего будет один или несколько конфигурационных файлов, определяющих параметры ядра для BSP. Можно задать конфигурацию поместив конфигурационные файлы в каталог, расположенный на том же уровне, где находится файл добавления для ядра, и имеющий такое же имя, которое задано для основного файла задания ядра. При выполнении этих условий достаточно просто указать файлы конфигурации оператором SRC_URI в файле добавления.

Предположим, например, что имеется набор опций конфигурации в файле network_configs.cfg. Можно поместить этот файл в каталог linux-yocto, а затем добавить оператор SRC_URI в файл добавления. Когда система OE будет собирать ядро, она найдет и применит конфигурационные опции.

     SRC_URI += "file://network_configs.cfg"

Для группировки связанных параметров в отдельные файлы применяется аналогичный подход. Ниже приведен пример группы раздельных конфигураций для Ethernet и графики в отдельных файлах с добавлением конфигурации с помощью операторов SRC_URI.

     SRC_URI += "file://myconfig.cfg \
                 file://eth.cfg \
                 file://gfx.cfg"

Другой переменной, которая может применяться в файле добавления для задания ядра, является FILESEXTRAPATHS. Оператор позволяет указать каталоги, в которых система сборки OE будет искать файлы и исправления в процессе обработки задания.

Существуют и другие методы группировки и задания параметров конфигурации. Например, при работе с локальной копией репозитория ядра можно выбрать мета-ветвь ядра, внести изменения и передать их в локальный пустой клон ядра. В результате это будет напрямую добавлять конфигурационные опции в мета-ветвь для
вашего
BSP. Параметры конфигурации скорей всего окажутся в этом месте в любом случае при добавлении BSP в YP.

Однако в общем случае служба поддержки YP старается переносить параметры конфигурации, заданные SRC_URI, в мета-ветвь ядра. Это не только позволяет разработчикам BSP не беспокоится о размещении этих конфигураций в ветвях, но и дает службе поддержки возможность применять «глобальные» знания о параметрах конфигурации, используемых множеством BSP в дереве. Это позволяет переносить базовые конфигурации в общие свойства.

2.3.2. Применение исправлений

Если у вас имеется одно исправление или небольшой их набор, которые вы хотите применить к исходным кодам ядра Linux, их можно применить как и для других заданий. Сначала patch-файлы копируются в каталог, добавленный оператором FILESEXTRAPATHS в ваш файл .bbappend, как описано в предыдущем параграфе, затем они указываются операторами SRC_URI.

Например, можно применить три набора исправления, добавив приведенные ниже строки в файл linux-yocto .bbappend на вашем уровне.

     SRC_URI += "file://0001-first-change.patch"
     SRC_URI += "file://0002-second-change.patch"
     SRC_URI += "file://0003-third-change.patch"

При следующем запуске BitBake для сборки ядра Linux изменение задания будет обнаружено и все указанные исправления будут применены к ядру перед его сборкой.

Более подробная информация о применении исправлений к ядру приведена в параграфах 2.4. Использование devtool для применения изменений к ядру и 2.5. Традиционные методы внесения изменений в ядро.

2.3.3. Изменение конфигурации ядра

Можно вносить изменения в конфигурационный файл ядра .config, применяемый
при сборке проекта, путем включения файла
defconfig и указания фрагментов конфигурации в SRC_URI [1] для применения к этому файлу.

Если имеется работоспособный файл конфигурации ядра Linux .config, который вы хотите использовать, просто скопируйте этот файл в нужный каталог ${PN} на уровне recipes-kernel/linux и переименуйте этот файл в defconfig. Затем добавьте в файл linux-yocto .bbappend на этом уровне строки

     FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
     SRC_URI += "file://defconfig"

Значение SRC_URI говорит системе сборки, как найти файл, а FILESEXTRAPATHS расширяет переменную FILESPATH (каталоги поиска), включая в нее каталог ${PN} для сохранения изменений в конфигурации.

Система сборки применяет конфигурацию из файла defconfig до применения последующих фрагментов конфигурации. Окончательная конфигурация ядра будет определяться комбинацией параметров в файле defconfig и предоставленных фрагментах конфигурации. Следует помнить, что фрагменты конфигурации система сборки применяет после defconfig и они могут менять заданную этим файлом конфигурацию.

В общем случае предпочтительным вариантом изменения конфигурации является создание соответствующего фрагмента. Например, если нужно добавить базовую поддержку последовательной консоли, можно создать в каталоге ${PN} файл 8250.cfg с приведенными ниже строками:

	CONFIG_SERIAL_8250=y
	CONFIG_SERIAL_8250_CONSOLE=y
	CONFIG_SERIAL_8250_PCI=y
	CONFIG_SERIAL_8250_NR_UARTS=4
	CONFIG_SERIAL_8250_RUNTIME_UARTS=4
	CONFIG_SERIAL_CORE=y
	CONFIG_SERIAL_CORE_CONSOLE=y

Далее включается этот фрагмент конфигурации и расширяется переменная FILESPATH в файле .bbappend, как показано ниже.

	FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
	SRC_URI += "file://8250.cfg"

При следующем запуске BitBake для сборки ядра Linux изменения в задании будут обнаружены, извлечены и применены к новой конфигурации ядра для сборки.

Более подробная информация приведена в разделе 2.6. Настройка конфигурации ядра.

2.3.4. Файл defconfig в дереве кода

Может оказаться желательной настройка конфигурации ядра из файла defconfig, размещенного в дереве исходных кодов ядра для целевой системы. По умолчанию система сборки OE ищет файлы defconfig на уровне, используемом для Metadata, который находится «вне дерева» и указывает их с помощью строк

     SRC_URI += "file://defconfig"

Если вы не хотите держать копии файлов defconfig на своем уровне, а разрешаете пользователям применять заданную по умолчанию конфигурацию из дерева ядра, сохраняя возможность добавлять изменения с помощью SRC_URI (например, путем добавления фрагментов), можно указать системе сборки OE использование файла defconfig, размещенного «в дереве ядра».

KBUILD_DEFCONFIG_KMACHINE ?= defconfig_file

Ниже приведен пример добавления переменной KBUILD_DEFCONFIG с common-pc и указания пути к файлу defconfig в дереве кода

     KBUILD_DEFCONFIG_common-pc ?= "/home/scottrif/configfiles/my_defconfig_file"

Помимо изменения вашего задания для ядра и предоставления файла defconfig нужно убедиться, что никакие файлы или операторы SRC_URI не используют других файлов defconfig (например, linux-machine.inc). Иными словами, при обнаружении машиной сборки операторов, указывающих файл defconfig вне дерева кода, эти операторы будут переопределять переменную KBUILD_DEFCONFIG. Описание переменной KBUILD_DEFCONFIG приведено в [1].

2.4. Использование devtool для применения изменений к ядру

Этапы этой процедуры показывают применение файлов исправлений (patch) к ядру с помощью SDK и devtool.

Перед выполнением процедуры убедитесь в том, что выполнены все этапы, указанные в параграфе 2.1.1. Подготовка к работе с использованием devtool.

Применение исправлений к ядру включает изменение или добавление параметров конфигурации имеющегося ядра, изменение или добавление заданий, нужных для поддержки конкретных аппаратных функций и даже изменение кода самого ядра.

Приведенный ниже пример включает простое изменение, заключающееся в добавлении вывода на консоль эмулятора QEMU в процессе загрузки с помощью функции printk в файле calibrate.c исходного кода ядра. Внесение изменений и загрузка с новым образом обеспечивают вывод на консоль эмулятора дополнительной информации. Пример является продолжением процедуры установки, описанной в параграфе 2.1.1. Подготовка к работе с использованием devtool.

  1. Проверка файлов с исходным кодом ядра. Сначала нужно использовать devtool для получения исходных кодов ядра. Убедитесь, что ваш терминал настроен на работу с SDK (см. 2.1.1. Подготовка к работе с использованием devtool).

    Для проверки кода используйте команду devtool, как показано ниже

         $ devtool modify linux-yocto

    Операция проверки имеет дефект, который может вызывать ошибку и показанное ниже сообщение

    ERROR: Taskhash mismatch 2c793438c2d9f8c3681fd5f7bc819efa versus
           be3a89ce7c47178880ba7bf6293d7404 for
           /path/to/esdk/layers/poky/meta/recipes-kernel/linux/linux-yocto_4.10.bb.do_unpack

    Это сообщение можно игнорировать.

  2. Редактирование файлов с исходным кодом. При внесении простых изменений в файлы следуйте описанной ниже процедуре.

    1. Смена рабочего каталога. Вывод предыдущего этапа указывает, где размещены файлы исходного кода (например, ~/poky_sdk/workspace/sources/linux-yocto). Перейдите в нужный каталог, прежде чем вносить изменения в файл calibrate.c.

           $ cd ~/poky_sdk/workspace/sources/linux-yocto
    2. Редактирование файла init/calibrate.cс включением представленного ниже текста.

           void calibrate_delay(void)
           {
               unsigned long lpj;
               static bool printed;
               int this_cpu = smp_processor_id();
      
               printk("*************************************\n");
               printk("*                                   *\n");
               printk("*        HELLO YOCTO KERNEL         *\n");
               printk("*                                   *\n");
               printk("*************************************\n");
      
              if (per_cpu(cpu_loops_per_jiffy, this_cpu)) {
                     .
                     .
                     .
  3. Сборка обновленного ядра. Для сборки ядра используется команда devtool

         $ devtool build linux-yocto
  4. Создание образа с новым ядром. Новый образ создается с помощью команды devtool build-image.

         $ cd ~
         $ devtool build-image core-image-minimal

    Если исходный образ был представлен файлом Wic, можно воспользоваться другим методом создания обновленного образа. Пример использования этого метода приведен на странице TipsAndTricks/KernelDevelopmentWithEsdk.

  5. Тестирование нового образа. В нашем примере можно запустить новый образ с QEMU для проверки изменений.

    1. Загрузка нового образа в эмуляторе QEMU

      $ runqemu qemux86
    2. Проверка изменений. Войдите в систему с именем root без пароля и введите приведенную ниже команду для просмотра вывода при загрузке.

      # dmesg | less

      Вывод должен содержать сообщения printk.

  6. Фиксация изменений. На консоли eSDK перейдите в каталог, где расположен измененный файл calibrate.c и используйте приведенные ниже команды Git для фиксации внесенных изменений.

         $ cd ~/poky_sdk/workspace/sources/linux-yocto
         $ git status
         $ git add init/calibrate.c
         $ git commit -m "calibrate: Add printk example"
  7. Экспорт исправлений и создание файла добавления. Для экспорта ваших изменений в качестве исправления (patche) и создания файла .bbappend file используйте приведенную ниже команду в консоли eSDK. В примере используется созданный ранее уровень meta-mylayer (см. п. 3 в параграфе 2.1.1. Подготовка к работе с использованием devtool).

         $ devtool finish linux-yocto ~/meta-mylayer

    После выполнения этой команды исправления и файл .bbappend будут находиться в каталоге ~/meta-mylayer/recipes-kernel/linux.

  8. Сборка образа с обновленным ядром. Сейчас можно собрать новый образ с учетом внесенных изменений. Для этого нужно выполнить приведенные ниже команды из каталога сборки в консоли BitBake.

         $ cd ~/poky/build
         $ bitbake core-image-minimal

2.5. Традиционные методы внесения изменений в ядро

Описанная здесь процедура показывает применение изменений (patch) к файлам ядра с использованием традиционных методов (т. е. без devtool и eSDK, описанных выше). Перед началом работы убедитесь в готовности системы к обновлению ядра (см. параграф 2.1.2. Подготовка к традиционной работе с ядром).

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

Пример в этом параграфе включает простое добавление вывода в консоль эмулятора QEMU при загрузке с помощью функции printk в файле ядра calibrate.c. Внесение этих изменений и загрузка нового образа обеспечат вывод на консоль дополнительной информации. Пример является продолжением процедуры настройки, описанной в параграфе 2.1.2. Подготовка к традиционной работе с ядром.

  1. Редактирование файлов с исходным кодом. Перед выполнением этого этапа убедитесь в наличии локальной копии Git-репозитория исходных кодов ядра (предполагается установка в соответствии с параграфом 2.1.2. Подготовка к традиционной работе с ядром).

    1. Смена рабочего каталога. Перейдите в каталог локальной копии репозитория Git с файлами ядра. В нашем примере для этого служит команда

           $ cd ~/linux-yocto-4.12/init
    2. Редактирование файла calibrate.c,
      в
      соответствии с приведенным ниже
      текстом.

           void calibrate_delay(void)
           {
               unsigned long lpj;
               static bool printed;
               int this_cpu = smp_processor_id();
      
               printk("*************************************\n");
               printk("*                                   *\n");
               printk("*        HELLO YOCTO KERNEL         *\n");
               printk("*                                   *\n");
               printk("*************************************\n");
      
              if (per_cpu(cpu_loops_per_jiffy, this_cpu)) {
                     .
                     .
                     .
  2. Фиксация и представление изменений. С помощью стандартных команд Git представьте внесенные правки.

         $ git add calibrate.c
         $ git commit -m "calibrate.c - Added some printk statements"

    Если этого не сделать, система сборки OE не учтет этих изменений.

  3. Обновление файла local.conf для указания файлов исходного кода. В дополнение к указанию в файле local.conf
    использовать
    kernel-modules и машину qemux86 можно указать обновленные файлы исходного кода ядра. Это делается с помощью операторов SRC_URI и SRCREV, как показано ниже.

    $ cd ~/poky/build/conf

    Добавляем приведенный ниже текст в файл local.conf.

    SRC_URI_pn-linux-yocto = "git:///path-to/linux-yocto-4.12;protocol=file;name=machine;branch=standard/base; \ git:///path-to/yocto-kernel-cache;protocol=file;type=kmeta;name=meta;branch=yocto-4.12;destsuffix=${KMETA}" SRCREV_meta_qemux86 = "${AUTOREV}" SRCREV_machine_qemux86 = "${AUTOREV}"

    Не забудьте заменить path-to реальным именем каталога с локальным репозиторием Git. Нужно также корректно указать ветви и типы машин. В примере указана ветвь standard/base и машина qemux86.

  4. Сборка образа. После правки исходного кода, фиксации и представления изменений и указания в файле local.conf файлов ядра можно использовать BitBake для сборки образа.

         $ cd ~/poky/build
         $ bitbake core-image-minimal
  5. Загрузка образа. Загрузите обновленный образ в эмулятор QEMU с помощью приведенных ниже команд (для входа в систему используется имя root без пароля):

         $ cd ~/poky/build
         $ runqemu qemux86
  6. Просмотр изменений. При загрузке QEMU можно увидеть сообщения, прокручивая экран вверх. Если прокрутка не поддерживается, воспользуйтесь командой

         # dmesg | less

    Вы увидите сообщения printk,
    выводимые
    в процессе загрузки
    .

  7. Генерация файла изменений. После проверки корректности работы можно создать файл *.patch в каталоге с исходным кодом ядра.

         $ cd ~/linux-yocto-4.12/init
         $ git format-patch -1
         0001-calibrate.c-Added-some-printk-statements.patch
  8. Перенос файла изменений на ваш уровень. Чтобы при последующих сборках учитывались внесенные изменений, нужно перенести созданный patch-файл на ваш уровень meta-mylayer. В нашем примере созданный ранее уровень размещается в домашнем каталоге и называется meta-mylayer. При создании уровня с помощью сценария yocto-create иерархия для поддержки исправлений не создается, поэтому перед переносом patch-файла нужно добавить соответствующие каталоги на вашем уровне, как показано ниже.

         $ cd ~/meta-mylayer
         $ mkdir recipes-kernel
         $ mkdir recipes-kernel/linux
         $ mkdir recipes-kernel/linux/linux-yocto

    После создания нужной иерархии можно переместить patch-файл с помощью команды

         $ mv ~/linux-yocto-4.12/init/0001-calibrate.c-Added-some-printk-statements.patch ~/meta-mylayer/recipes-kernel/linux/linux-yocto
  9. Создание файла добавления. В заключение нужно создать файл linux-yocto_4.12.bbappend и добавить в него операторы, которые позволят системе сборки OE найти исправления. Этот файл должен размещаться в каталоге recipes-kernel/linux и называться linux-yocto_4.12.bbappend.
    Содержимое
    файла показано ниже.

         FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
    
         SRC_URI_append = " file://0001-calibrate.c-Added-some-printk-statements.patch"

    Операторы FILESEXTRAPATHS и SRC_URI позволяют системе сборки OE найти patch-файл.

    Дополнительная информация о файлах дополнения и «заплатках» представлена в параграфах 2.3.1. Создание файла добавления и 2.3.2. Применение исправлений. Можно также обратиться к разделу Using .bbappend Files in Your Layer [4].

    Для последующей сборки core-image-minimal и просмотра влияния изменений можно устранить временные файлы исходного кода в poky/build/tmp/work/... и побочные эффекты прежней сборки с помощью команд

         $ cd ~/poky/build
         $ bitbake -c cleanall yocto-linux
         $ bitbake core-image-minimal -c cleanall
         $ bitbake core-image-minimal
         $ runqemu qemux86

2.6. Настройка конфигурации ядра

Настройка ядра в YP заключается в том, чтобы обеспечить наличие в файле .config всей нужной информации для создаваемого образа. Можно использовать инструмент menuconfig и фрагменты конфигурации, чтобы создать нужный файл .config. Можно сохранить проверенную конфигурацию в файле defconfig,
который
система сборки будет использовать для
настройки ядра
.

В этом разделе описано использование menuconfig, создание и применение фрагментов конфигурации, а также изменение в интерактивном режиме файла .config с нужной конфигурацией. Конфигурация ядра описана также в разделе 2.3.3. Изменение конфигурации ядра.

2.6.1. Использование menuconfig

Простейшим способом задать конфигурацию ядра является инструмент menuconfig [2]. Это позволяет настраивать конфигурацию в интерактивном режиме с доступом к справке по конфигурационным параметрам. Для работы с menuconfig в среде YP требуется выполнить ряд условий, приведенных ниже

  • Поскольку menuconfig запускается с использованием BitBake, нужно настроить рабочее окружение с помощью сценария oe-init-build-env в вашем каталоге сборки [2].

  • Нужно проверить наличие конфигурации вашей сборки в каталоге исходных кодов [2].

  • На сборочном хосте должны быть установлены пакеты5:

    libncurses5-dev

    libtinfo-dev

Приведенные ниже команды инициализируют окружение BitBake, запускают задачу do_kernel_configme [2] и инструмент menuconfig. Предполагается что каталог верхнего уровня в Source Directory имеет имя ~/poky.

     $ cd poky
     $ source oe-init-build-env
     $ bitbake linux-yocto -c kernel_configme -f
     $ bitbake linux-yocto -c menuconfig

После запуска menuconfig на экране появится стандартный интерфейс настройки конфигурационных параметров ядра. Внесите нужные изменения и завершите работу с сохранением результатов в конфигурационном файле .config.

Файл .config можно использовать в качестве defconfig (см. параграфы 2.3.3. Изменение конфигурации ядра, 2.3.4. Файл defconfig в дереве кода и 2.6.2. Создание файла defconfig).

Рассмотрим пример настройки параметров CONFIG_SMP для ядра проекта linux-yocto-4.12. Система сборки OE распознает это ядро как linux-yocto по Metadata (например, PREFERRED_VERSION_linux-yocto
?= "12.4%"
).

После запуска menuconfig установите нужные параметры конфигурации ядра и сохраните файл. В нашем примере отключается опция CONFIG_SMP путем снятия отметки Symmetric Multi-Processing Support (клавиша N). После обновления файла .config система сборки будет использовать его для настройки ядра в процессе сборки. Файл можно посмотреть в каталоге tmp/work/. Реальный файл .config
для использования при сборке будет размещаться в дереве исходных кодов ядра. Например, при сборке ядра Linux Yocto на основе linux-yocto-4.12 для создания образа QEMU для архитектуры x86 architecture файл .config будет находиться в каталоге poky/build/tmp/work/qemux86-poky-linux/linux-yocto/4.12.12+gitAUTOINC+eda4d18…967-r0/linux-qemux86-standard-build/.config. Имя каталога намеренно указано не полностью с целью сокращения. Кроме того, часть пути может меняться в зависимости от собираемого ядра.

В файле .config указаны параметры конфигурации ядра. В нашем примере будет строка, отключающая поддержку симметричной многопроцессорной обработки

     # CONFIG_SMP is not set

Хорошим методом изоляции изменений конфигурации является использование комбинации menuconfig и простых команд оболочки. Перед изменением конфигурации с помощью menuconfig
скопируйте
файл
.config и переименуйте копию (чтобы понять, какая конфигурация находится в файле), а затем используйте menuconfig для внесения требуемых изменений. После сохранения можно сравнить новый файл с прежним. Различия между файлами можно использовать для создания фрагментов конфигурации на вашем уровне ядра.

2.6.2. Создание файла defconfig

Файл defconfig в контексте YP зачастую является копией файла .config из каталога сборки или дерева исходных кодов ядра, перенесенной в пространство задания. Файл defconfig можно использовать для сохранения проверенной конфигурации ядра и система сборки OE будет создавать из него финальный файл .config.

YP без готового проекта не включает файлов defconfig и .config. Финальный файл .config,
используемый
для настройки ядра, создает система
сборки OE
.

Для создания файла defconfig
следует
взять полный файл .config рабочей конфигурации
ядра
Linux и скопировать его в подходящий каталог ${PN} в каталоге recipes-kernel/linux вашего уровня (например, ~/meta-mylayer/recipes-kernel/linux/linux-yocto/defconfig), а затем переименовать в defconfig. После этого в файл linux-yocto .bbappend на вашем уровне нужно добавить строки

     FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
     SRC_URI += "file://defconfig"

Значение SRC_URI говорит системе сборки, как найти файл, а FILESEXTRAPATHS расширяет переменную FILESPATH (каталоги поиска), включая в нее каталог ${PN} для сохранения изменений в конфигурации.

Система сборки применяет конфигурацию из файла defconfig до применения последующих фрагментов конфигурации. Окончательная конфигурация ядра будет определяться комбинацией параметров в файле defconfig и предоставленных фрагментах конфигурации. Следует помнить, что фрагменты конфигурации система сборки применяет после defconfig и они могут менять заданную этим файлом конфигурацию (см. 2.3.3. Изменение конфигурации ядра).

2.6.3. Создание фрагментов конфигурации

Фрагменты конфигурации являются просто опциями ядра, указанными в файлах, размещенных там, где система сборки OE может найти и применить их. Эти фрагменты применяются после рассмотрения опций, заданных в файле defconfig. Таким образом, конфигурация ядра определяется набором опций в файле defconfig
с
учетом дополнений и изменений, вносимых
представленными фрагментами конфигурации
. Синтаксически фрагменты конфигурации идентичны содержимому файла .config в каталоге сборки (см. параграф 2.6.1. Использование menuconfig).

Создание фрагментов конфигурации достаточно просто. Одним из вариантов является использование команд системной оболочки. Например, можно добавить опцию в имеющийся фрагмент my_smp.cfg с помощью команды

     $ echo "CONFIG_SMP=y" >> my_smp.cfg

Все файлы с фрагментами конфигурации должны иметь расширение .cfg,
чтобы
система сборки
OE могла распознавать их.

Другим методом создания фрагментов конфигурации является использование различий между двумя конфигурационными файлами, один из которых создан ранее и сохранен, а другой недавно создан с помощью menuconfig.

  1. Начальная настройка конфигурации ядра с помощью команды

         $ bitbake linux-yocto -c kernel_configme -f

    Это обеспечит создание файла .config по известным источникам. В некоторых ситуациях состояние сборки может быть не известно, поэтому лучше выполнять эту команду до запуска menuconfig.

  2. Настройка конфигурации с помощью menuconfig

         $ bitbake linux-yocto -c menuconfig
  3. Создание фрагмента конфигурации. Введите команду diffconfig для создания фрагмента конфигурации fragment.cfg, который будет помещен в каталог ${WORKDIR}

         $ bitbake linux-yocto -c diffconfig

Команда diffconfig создает файл со списком назначений переменных конфигурации ядра CONFIG_. Использование вывода программы для создания фрагмента конфигурации описано в параграфе 2.3.3. Изменение конфигурации ядра. Этот метод можно использовать и при создании фрагментов конфигурации для BSP (см. 3.3.5. Описания BSP).

Файлы с фрагментами конфигурации можно разместить в области, указанной переменной SRC_URI,
как
это задано в файле
bblayers.conf, размещенном в каталоге вашего уровня. Система сборки OE заберет эти фрагменты и добавит в конфигурацию ядра. Предположим, например, размещение некоторых опций конфигурации в файле myconfig.cfg. Если файл размещен в каталоге linux-yocto,
который
находится в одном каталоге с файлом
добавления для ядра и в этот файл включены
приведенные ниже операторы, конфигурационные
опции будут найдены и применены при
сборке ядра.

     FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
     SRC_URI += "file://myconfig.cfg"

Как отмечено выше, можно сгруппировать связанные конфигурации в несколько файлов и указать их в операторе SRC_URI. Например, можно сделать разные фрагменты конфигурации для Ethernet и графики, указав их в операторе SRC_URI внутри файла дополнения.

     SRC_URI += "file://myconfig.cfg \
            file://eth.cfg \
            file://gfx.cfg"

2.6.4. Проверка корректности конфигурации

Для проверки конфигурации можно использовать задачу do_kernel_configcheck с помощью команды

     $ bitbake linux-yocto -c kernel_configcheck -f

При работе этой задачи выдаются предупреждения об отсутствии запрошенной конфигурации в финальном файле .config или переопределении правил конфигурации во фрагменте аппаратной конфигурации.

Для запуска этой задачи в системе сборки должен быть подготовленный файл .config. Создание конфигурационного файла описано в параграфе 2.6.1. Использование menuconfig.

Ниже приведен пример вывода задачи do_kernel_configcheck.

     Loading cache: 100% |########################################################| Time: 0:00:00
     Loaded 1275 entries from dependency cache.
     NOTE: Resolving any missing task queue dependencies

     Build Configuration:
         .
         .
         .

     NOTE: Executing SetScene Tasks
     NOTE: Executing RunQueue Tasks
     WARNING: linux-yocto-4.12.12+gitAUTOINC+eda4d18ce4_16de014967-r0 do_kernel_configcheck:
         [kernel config]: specified values did not make it into the kernel's final configuration:

     ---------- CONFIG_X86_TSC -----------------
     Config: CONFIG_X86_TSC
     From: /home/scottrif/poky/build/tmp/work-shared/qemux86/kernel-source/.kernel-meta/configs/standard/bsp/common-pc/common-pc-cpu.cfg
     Requested value:  CONFIG_X86_TSC=y
     Actual value:


     ---------- CONFIG_X86_BIGSMP -----------------
     Config: CONFIG_X86_BIGSMP
     From: /home/scottrif/poky/build/tmp/work-shared/qemux86/kernel-source/.kernel-meta/configs/standard/cfg/smp.cfg
           /home/scottrif/poky/build/tmp/work-shared/qemux86/kernel-source/.kernel-meta/configs/standard/defconfig
     Requested value:  # CONFIG_X86_BIGSMP is not set
     Actual value:


     ---------- CONFIG_NR_CPUS -----------------
     Config: CONFIG_NR_CPUS
     From: /home/scottrif/poky/build/tmp/work-shared/qemux86/kernel-source/.kernel-meta/configs/standard/cfg/smp.cfg
           /home/scottrif/poky/build/tmp/work-shared/qemux86/kernel-source/.kernel-meta/configs/standard/bsp/common-pc/common-pc.cfg
           /home/scottrif/poky/build/tmp/work-shared/qemux86/kernel-source/.kernel-meta/configs/standard/defconfig
     Requested value:  CONFIG_NR_CPUS=8
     Actual value:     CONFIG_NR_CPUS=1


     ---------- CONFIG_SCHED_SMT -----------------
     Config: CONFIG_SCHED_SMT
     From: /home/scottrif/poky/build/tmp/work-shared/qemux86/kernel-source/.kernel-meta/configs/standard/cfg/smp.cfg
           /home/scottrif/poky/build/tmp/work-shared/qemux86/kernel-source/.kernel-meta/configs/standard/defconfig
     Requested value:  CONFIG_SCHED_SMT=y
     Actual value:



     NOTE: Tasks Summary: Attempted 288 tasks of which 285 didn't need to be rerun and all succeeded.

     Summary: There were 3 WARNING messages shown.           

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

Дополнительная информация о настройке конфигурации приведена в параграфе 2.6.1. Использование menuconfig.

2.6.5. Тонкая настройка конфигурации ядра

Вы можете проверить корректность и эффективность файла .config,
просматривая
вывод аудита фрагментов конфигурации
ядра, отмечая проблемы и внося изменения,
а затем повторяя процедуру проверки
.

В процессе сборки ядра выполняется задача do_kernel_configcheck,
проверяющая
конфигурацию ядра путем сравнения
финального файла
.config со входными файлами. В процессе проверки выдаются предупреждения в случае наличия перечисленных ниже проблем.

  • Запрошенная опция не включена в финальный файл .config.

  • Опция указана более одного раза в одном фрагменте конфигурации.
  • Был переопределен элемент конфигурации, помеченный как обязательный (required).
  • Для платы переопределена опция, не относящаяся к ней.
  • Указанные опции не пригодны для собираемого ядра (недопустимо их присутствие где-либо).

Задача do_kernel_configcheck может также сообщать о переопределении опций в процессе обработки.

В каждом выводимом предупреждении указывается файл, содержащий список опций и указатель на фрагмент конфигурации, где он определен. Для упрощения настройки используйте перечисленные ниже операции.

  1. Используйте рабочую конфигурацию. Начните с полной конфигурации, которая заведомо работает (проверена в плане сборки ядра и его загрузки).

  2. Запустите задачи настройки и проверки конфигурации. Поочередно запустите задачи do_kernel_configme и do_kernel_configcheck,
    как
    показано ниже

         $ bitbake linux-yocto -c kernel_configme -f
         $ bitbake linux-yocto -c kernel_configcheck -f
  3. Обработайте результаты. Возьмите список файлов из предупреждений задачи do_kernel_configcheck и выполните перечисленные ниже операции.

    • Удалите значения, которые переопределены во фрагменте, но не меняют финальный файл .config.

    • Проанализируйте и при необходимости удалите из файла .config опции, которые переопределяют требуемые настройки.

    • Проанализируйте и при необходимости удалите не относящиеся к вашей плате настройки.

    • Удалите повторяющиеся и недействительные опции.

  1. Повторите задачи настройки и проверки конфигурации. После обработки результатов аудита конфигурации ядра запустите повторно задачи do_kernel_configme и do_kernel_configcheck для просмотра результатов своих правок. Если проблемы остались, вернитесь к п. 3.

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

2.7. Извлечение значений переменных

Иногда полезно бывает определить, во что преобразуется переменная в процессе сборки. Можно проверить значения переменных путем просмотра вывода команды bitbake
-e
. Команда выводит достаточно много информации, поэтому лучше направить ее в текстовый файл, которым можно будет просмотреть.

$ bitbake -e virtual/kernel > some_text_file

Этот файл будет содержать значения каждой переменной, преобразуемой и используемой системой сборки OE.

2.8. Работа с «грязной» строкой версии ядра

Если при сборке ядра строка версии имеет суффикс +dirty или -dirty, это говорит о незафиксированных изменениях в каталоге исходных кодов ядра. Для очистки строки версии используйте описанные ниже процедуры.

  1. Поиск не зафиксированных изменений. Перейдите в каталог локального репозитория Git (каталог исходных кодов) и найдите измененные, добавленные или удаленные файлы с помощью команды

         $ git status
  2. Зафиксируйте изменения. Найденные изменения следует зафиксировать (commit) в дереве исходных кодов ядра независимо от того, планируется ли сохранение, экспорт или использование внесенных изменений.

         $ git add
         $ git commit -s -a -m "getting rid of -dirty"
  3. Повторная сборка ядра. После фиксации изменений следует заново собрать ядро.

    В зависимости от конкретного процесса разработки ядра команда повторной сборки может меняться. Информация о сборке ядра с помощью devtool
    представлена
    в параграфе 2.4. Использование devtool для применения изменений к ядру,
    а для использования традиционных
    методов - в параграфе 2.5. Традиционные методы внесения изменений в ядро
    .

2.9. Работа со своими исходными кодами

Если вы не можете работать с одной из версий ядра, поддерживаемых имеющимися заданиями linux-yocto, вы можете применять инструменты YP для работы со своими исходными кодами ядра. В таких случаях вы не сможете воспользоваться имеющимися метаданными ядра и результатами стабилизации исходных кодов linux-yocto. Однако это не помешает управлять своими метаданными в том же формате, который применяется в linux-yocto. Поддержка совместимых форматов облегчит слияние с linux-yocto в будущей версии ядра с взаимной поддержкой.

Чтобы помочь при работе со своими исходными кодами, YP предоставляет специальное задание linux-yocto (linux-yocto-custom.bb), использующее исходные коды с сайта kernel.org и инструменты для управления метаданными ядра. Это задание можно найти в репозитории poky Git репозитория исходных кодов YP

     poky/meta-skeleton/recipes-kernel/linux/linux-yocto-custom.bb

Ниже описаны базовые этапы работы со своим деревом исходных кодов

  1. Создание копии задания для ядра. Скопируйте задание linux-yocto-custom.bb на свой уровень и дайте файлу осмысленное имя. В имя следует включить используемую версию ядра Yocto Linux (например, linux-yocto-myproject_4.12.bb, где 4.12 указывает номер базовой версии ядра Linux, с которой вы будете работать).

  2. Создание каталога для файлов с исправлениями. В том же каталоге внутри своего уровня создайте соответствующий каталог для хранения ваших файлов изменений (patch) и конфигурационных файлов (например, linux-yocto-myproject).

  3. Обеспечение наличия конфигурации. Убедитесь в наличии файла defconfig или файлов с фрагментами конфигурации на своем уровне. При использовании задания linux-yocto-custom.bb нужно будет задать конфигурацию. Если файла defconfig нет, введите из каталога с исходными кодами ядра команду

         $ make defconfig

    После завершения работы команды скопируйте полученный файл .config в каталог files на своем уровне, переименуйте его в defconfig и добавьте в переменную SRC_URI для задания.

    Выполнение команды make
    defconfig
    создает конфигурацию с принятыми по умолчанию опциями для вашей архитектуры, определенными вашим ядром. Однако пригодность конфигурации для вашего конкретного случая не гарантируется. Особенно велика вероятность возникновения проблем для архитектуры, отличающейся от x86. Для использования файлов в такой архитектуре нужно указать более конкретно вашу плату (например,
    для
    arm следует заглянуть в каталог arch/arm/configs и использовать наиболее подходящий вариант defconfig
    в качестве стартовой конфигурации).

  4. Редактирование задания. Отредактируйте в своем задании перечисленные ниже переменные с учетом потребностей проекта.

    • SRC_URI. В этой переменной следует указать репозиторий Git, который использует один из поддерживаемых протоколов сборщика Git (file, git, http
      и
      т. п.
      ). В SRC_URI следует также указать defconfig или файлы фрагментов конфигурации. Образец задания включает пример SRC_URI.

    • LINUX_VERSIONиспользуемая версия ядра Linux (например, 4.12).

    • LINUX_VERSION_EXTENSION - значение опции CONFIG_LOCALVERSION, которое будет включено в собираемое ядро и доступно по команде uname.

    • SRCREV - идентификатор фиксации (commit ID), из которой будет выполняться сборка.

    • PR - номер сборки, увеличиваемый каждый раз для указания системе OE факта изменения задания.

    • PV - принятое по умолчанию значение PV обычно адекватно. Оно комбинирует LINUX_VERSION с выпуском SCM6 из переменной SRCPV и дает строку вида

      3.19.11+git1+68a635bf8dfb64b02263c1ac80c948647cc76d5f_1+218bd8d2022b9852c60d32f0d770931e3cf343e2

      Большой размер строки PV позволяет гарантировать использование именно тех источников, из которых планируется собирать задание.

    • COMPATIBLE_MACHINE
      -
      список машин, поддерживаемых новым заданием. Для этой переменной в примере по умолчанию используется регулярное выражение, которому соответствует лишь пустая строка «(^$)». Это вызывает явный отказ при сборке, поэтому переменную нужно изменить в соответствии со списком машин, которые будет поддерживать новое задание. Например, поддержку машин qemux86 и qemux86-64 можно указать в форме

           COMPATIBLE_MACHINE = "qemux86|qemux86-64"
  5. Настройка вашего задания. Выполните подобающую настройку своего задания, как описано для имеющегося задания linux-yocto (см. параграф 2.3. Изменение существующего задания).

2.10. Работа с модулями вне дерева исходных кодов

В этом разделе описаны этапы сборки внешних (out-of-tree) модулей на целевой платформе и встраивания таких модулей в сборку.

2.10.1. Сборка внешних модулей на целевой платформе

Хотя традиционная модель разработки YP будет включать модули ядра в обычный процесс сборки, может возникнуть потребность в сборке модуля на целевой платформе. Это возможно в тех случаях, когда платформа имеет производительность, достаточную для компиляции исходного кода. Однако перед выбором такого подхода следует оценить возможности использования кросс-компиляции модуля на сборочном хосте.

Если вы хотите собрать внешний модуль на целевой платформе, вам потребуется выполнить на ней несколько операций, описанных ниже. Пакет kernel-dev устанавливается по умолчанию во все образы *.sdk, а kernel-devsrcна большинство таких образов. Однако потребуется создать некоторые сценарии до попытки собрать внешние модули на целевой платформе, использующей такой образ.

Перед попыткой собрать внешний модуль нужно войти в систему платформы как пользователь root и перейти в каталог /usr/src/kernel, а затем собрать сценарии.

     # cd /usr/src/kernel
     # make scripts                

Поскольку все задания для образов SDK включают dev-pkgs, пакет kernel-dev будет установлен как часть образа SDK, а пакеты kernel-devsrcкак часть соответствующих образов SDK. В SDK применяются сценарии для сборки внешних модулей. После перехода в указанный каталог и создания сценариев вы сможете собирать внешние модули.

2.10.2. Встраивание внешних модулей

Хотя всегда предпочтительней работать с кодами, встроенными в дерево ядра Linux, при необходимости собрать внешний модуль ядра можно использовать задание hello-mod.bb в качестве образца для подготовки нужного задания по сборке внешнего модуля. Упомянутый шаблон находится в репозитории Git YP Source Repository

     poky/meta-skeleton/recipes-kernel/hello-mod/hello-mod_0.1.bb

Для начала работы скопируйте этот файл задания на свой уровень и дайте ему осмысленное имя (например, mymodule_1.0.bb). В том же каталоге создайте подкаталог с именем files,
где
будут храниться файлы исходного кода,
исправления и другие файлы, требуемые
для сборки модуля, не включенного в
дерево исходных кодов ядра
. Затем отредактируйте задание в соответствии с потребностями модуля. Обычно требуется установить значения переменных:

В зависимости от системы сборки, используемой для модулей, могут потребоваться некоторые дополнительные настройки. Например, типичный файл Makefile для модуля имеет вид, похожий на файл из шаблона hello-mod.

     obj-m := hello.o

     SRC := $(shell pwd)

     all:
         $(MAKE) -C $(KERNEL_SRC) M=$(SRC)

     modules_install:
         $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install
     ...                

Важно отметить здесь переменную KERNEL_SRC. Класс module устанавливает для нее и переменной KERNEL_PATH значение ${STAGING_KERNEL_DIR} с необходимой для сборки модуля информацией о ядре Linux. Если в Makefile
модуля
используется другая переменная, вы
можете переопределить ее на этапе
do_compile или создать файл исправления для Makefile,
позволяющий
работать с переменными
KERNEL_SRC и KERNEL_PATH.

После подготовки задания вы наверняка захотите включить модуль в свои образы. Для этого следует ознакомиться с описаниями перечисленных ниже переменных в [1] и установить для них значения, подходящие для целевой машины.

Модули часто не требуются при загрузке и могут быть исключены из некоторых конфигураций сборки. Для повышения гибкости используйте переменную

     MACHINE_EXTRA_RRECOMMENDS += "kernel-module-mymodule"

Значение переменной выводится путем добавления имени файла модуля без расширения .ko.

Поскольку переменная является RRECOMMENDS, а не RDEPENDS, сборка не будет завершаться ошибкой в результате невозможности включения модуля в образ.

2.11. Проверка изменений и фиксации

При работе с ядром часто возникает вопрос о том, какие изменения были внесены в дерево исходных кодов. Можно воспользоваться утилитой grep в рекурсивном режиме, но Git лучше подходит для просмотра или поиска изменений в дереве кодов ядра.

2.11.1. Поиск изменений в ядре

Ниже приведено несколько примеров использования команд Git для поиска изменений в ядре. В примерах предполагается, что до фиксации диапазона внесенных изменений история kernel.org смешана с историей изменений ядра в YP. Можно сформировать диапазоны изменений путем использования имен ветвей из дерева ядра в качестве верхнего и нижнего маркеров фиксации (commit) с помощью команд Git. Имена ветвей можно получить с помощью web-интерфейса репозитория YP на странице http://git.yoctoproject.org.

Для просмотра всего диапазона изменений используйте команду git
whatchanged
с указанием диапазона фиксации для ветви (commit..commit).

Ниже приведен пример просмотра изменений в ветви emenlow ядра linux-yocto-3.19. Нижним маркером служит фиксация, связанная с ветвью standard/base, а верхний маркер связан с фиксацией ветви standard/emenlow.

     $ git whatchanged origin/standard/base..origin/standard/emenlow

Для просмотра кратких (в одну строку) сводок изменений служит команда git
log

     $ git log --oneline origin/standard/base..origin/standard/emenlow

Для просмотра различий в коде в результате изменений служит команда

     $ git diff origin/standard/base..origin/standard/emenlow

Для просмотра сообщений в журнале фиксации и текста различий служит команда

     $ git show origin/standard/base..origin/standard/emenlow

Приведенная ниже команда создает отдельный patch-файл для каждого изменения, размещая файлы для каждой фиксации в каталоге Documents.

     $ git format-patch -o $HOME/Documents origin/standard/base..origin/standard/emenlow

2.11.2. Просмотр изменений конкретной функции или ветви

Теги в дереве ядра YP делят изменения конфигурации по значимым функциям или ветвям. Команда git
show
<tag> позволяет видеть изменения по тегам. Например, приведенная ниже команда покажет изменения для systemtap.

     $ git show systemtap

Можно использовать команду git
branch --contains
<tag> для просмотра ветвей, содержащих определенную возможность. Например, приведенная ниже команда покажет ветви с возможностью systemtap.

     $ git branch --contains systemtap

2.12. Добавление функций ядра recipe-space

Можно добавить функции ядра в пространство заданий recipe-space с помощью переменной KERNEL_FEATURES и указания пути к файлу .scc в операторе SRC_URI. При добавлении функций таким способом система сборки OE проверяет наличие всех функций и при отсутствии той или иной останавливает сборку. Функции ядра обрабатываются после настройки и внесения изменений (patch). Поэтому добавление возможностей таким путем гарантирует наличие и включение соответствующих функций без необходимости полного аудита дополнений SRC_URI
в других уровнях.

Возможность ядра добавляется как часть переменной KERNEL_FEATURES с указанием пути к файлу .scc относительно корня метаданных ядра. Система сборки OE ищет все формы метаданных ядра по оператору SRC_URI
независимо
от их размещения в кэше (
kernel-cache), метаданных ядра системы или recipe-space (часть задания для ядра). Дополнительная информация о метаданных приведена в параграфе 3.4. Размещение метаданных ядра.

При указании файла возможностей .scc в операторе SRC_URI система сборки OE добавляет каталог с файлом .scc и все его подкаталоги в путь поиска функций ядра. Благодаря поиску в подкаталогах, достаточно указать один файл .scc в операторе SRC_URI для множества возможностей ядра.

Рассмотрим пример с добавлением возможности test.scc при сборке ядра.

  1. Создание файла возможности. Создается файл .scc и указывается в операторе SRC_URI
    как другие файлы исправлений,
    .cfg или элементов сборки.

    • Каталог с файлом .scc должен быть включен в путь поиска сборщика, как это делается для файлов .patch.

    • Можно создать дополнительные файлы .scc в том же каталоге или его подкаталогах.

Предположим, что функция test.scc добавлена в файл test.scc,
как
показано ниже.

my_recipe | +-linux-yocto | +-test.cfg +-test.scc

В этом примере каталог linux-yocto включает файл возможности test.scc и фрагмент конфигурации test.cfg.

  1. Добавление файла возможности в SRC_URI. Включите файл .scc в оператор SRC_URI вашего задания

         SRC_URI_append = " file://test.scc"

    Пробел в начале значения важен, поскольку путь добавляется в конец имеющегося пути.

  2. Указание возможности как функции ядра. Добавьте возможность в оператор KERNEL_FEATURES.

         KERNEL_FEATURES_append = " test.scc"

    Система сборки OE обработает эту возможность при сборке ядра.

    При наличии других возможностей «ниже» test.scc они размещаются в дереве каталога с файлом test.scc.

Глава 3. Работа с расширенными метаданными (yocto-kernel-cache)

3.1. Обзор

В дополнение к поддержке фрагментов конфигурации и patch-файлов инструменты YP также поддерживают обширный набор метаданных, которые можно применять для задания комплексных правил и поддержки BSP. Назначение Metadata и инструментов для поддержки заключается в помощи при управлении сложными конфигурациями и исходными кодами для поддержки множества BSP и типов ядер Linux.

Метаданные ядра (Kernel Metadata) размещаются во многих местах, одним из которых является репозиторий Git yocto-kernel-cache, указанный под заголовком Yocto Linux Kernel на странице Yocto Project Source Repositories.

Инструменты для работы с ядром (kern-tools) также размещены в этом репозитории под заголовком Yocto Linux Kernel. Задание для сборки этих инструментов размещено в файле meta/recipes-kernel/kern-tools/kern-tools-native_git.bb каталога исходных кодов (например, poky).

3.2. Использование метаданных ядра в задании

Как отмечено выше, YP включает метаданные ядра, размещенные в репозитории Git yocto-kernel-cache. Эти метаданные определяют пакеты BSP, которые соответствуют определениям в заданиях linux-yocto для BSP. Пакет BSP представляет собой совокупность правил для ядра и разрешенных (включенных) функций оборудования. На BSP можно влиять из задания linux-yocto.

Задание для ядра Linux с метаданными ядра (например, унаследованными из файла linux-yocto.inc) называют заданием в стиле linux-yocto. Каждое такое задание определяет переменную KMACHINE, значение которой обычно совпадает со значением переменной MACHINE, используемой BitBake. Однако в некоторых случаях переменная может указывать базовую платформу для MACHINE.

Множество BSP могут использовать общее имя KMACHINE, если они собираются с использованием одного описания BSP. Например, множество BSP на базе Corei7 использует KMACHINE=intel-corei7-64. Важно понимать, что KMACHINE служит просто для сопоставления с ядром, а MACHINE указывает тип машины на уровне BSP. Однако даже с учетом этого различия переменные могут иметь одинаковые значения (см. параграф 3.3.5. Описания BSP).

Каждое задание в стиле linux-yocto должно также указывать ветвь репозитория ядра Linux, используемую для сборки ядра, в переменной KBRANCH. Значение KBRANCH можно использовать для определения дополнительной ветви (обычно с переопределением машины), как показано ниже (из уровня meta-yocto-bsp).

     KBRANCH_edgerouter = "standard/edgerouter"

Задания в стиле linux-yocto могут также определять переменные KERNEL_FEATURES и LINUX_KERNEL_TYPE.

Переменная LINUX_KERNEL_TYPE определяет тип ядра, используемый при сборке конфигурации (по умолчанию standard). Вместе с KMACHINE переменная LINUX_KERNEL_TYPE определяет аргументы поиска, используемые инструментами ядра для нахождения нужных описаний в метаданных ядра, с которыми будет выполняться сборка и настройка. Задания linux-yocto определяют типы standard, tiny и preempt-rt (см. параграф 3.3.4. Типы ядер).

В процессе сборки kern-tools выполняет поиск файла описания BSP, наиболее точно соответствующего переменным KMACHINE и LINUX_KERNEL_TYPE, переданным
из задания
. Инструменты используют первое найденное описание BSP, которое соответствует обеим переменным. Если описание не найдено, выдается предупреждение. Поиск выполняется сначала для переменной KMACHINE, а затем для LINUX_KERNEL_TYPE. Если не удается найти частичного совпадения, будут применяться исходные коды из KBRANCH и конфигурация, заданная в SRC_URI.

Переменную KERNEL_FEATURES можно применять для включения возможностей (фрагменты конфигурации, patch-файлы), которые не были указаны в KMACHINE и LINUX_KERNEL_TYPE. Например, для включения свойства из файла features/netfilter/netfilter.scc следует указать

     KERNEL_FEATURES += "features/netfilter/netfilter.scc"

Для включения свойства cfg/sound.scc для машины qemux86 следует использовать

     KERNEL_FEATURES_append_qemux86 = " cfg/sound.scc"

Значения элементов KERNEL_FEATURES зависят от их расположения внутри метаданных ядра. Приведенные здесь примеры взяты из репозитория yocto-kernel-cache,
каждая
из ветвей которого содержит на верхнем
уровне каталоги
features и cfg (см. параграф 3.3. Синтаксис метаданных ядра).

3.3. Синтаксис метаданных ядра

Метаданные ядра включают три основных типа файлов — описания scc [1], фрагменты конфигурации и patch-файлы. Файлы scc определяют переменные и включают или иным способом указывают любые из 3 упомянутых типов файлов. Файлы описания служат для объединения всех типов метаданных ядра в единое описание исходных файлов и конфигурации, требуемое для сборки ядра, адаптированного к конкретной машине.

Файлы описаний scc служат для определения двух фундаментальных типов метаданных ядра:

  • возможности;

  • пакеты поддержки плат (BSP).

Возможности объединяют исходные файлы в форме исправлений (patch) и фрагментов конфигурации в модуль для многократного использования. Возможности можно применять для реализации концептуально разделенных описаний метаданных ядра, таких как фрагменты конфигурации, простые исправления, сложные функции и типы ядра. Тип ядра определяет базовые функции ядра и правила их применения в BSP.

BSP определяют зависящие от оборудования возможности и объединяют их с типом ядра для создания окончательного описания того, что нужно собрать.

Хотя синтаксис метаданных ядра не требует логического разделения фрагментов конфигурации, исправлений, свойств и типов ядра, такое разделение является хорошим тоном. Ниже приведена рекомендуемая иерархия метаданных.

base/ bsp/ cfg/ features/ ktypes/ patches/ 

Каталог bsp содержит описания BSP, а в остальных каталогах описаны свойства (функции). Отделение bsp от остальной структуры способствует осмыслению предполагаемого использования. Приведенные ниже рекомендации помогут разместить файлы scc в этой структуре.

  • Файлы, содержащие только фрагменты конфигурации, следует помещать в каталог cfg.

  • Файлы, содержащие лишь исправления исходного кода, следует помещать в каталог patches.

  • Файлы, описывающие важные свойства (major feature), зачастую объединяя исходные файлы и конфигурации, следует помещать в каталог features.

  • Файлы, объединяющие не относящуюся к оборудованию конфигурацию и исправления для задания политики ядра или его типа, которые могут применяться разными BSP, следует помещать в каталог ktypes.

Отмеченные различия могут оказаться размытыми (особенно функции вне основного дерева, которые со временем попадают в него). Кроме того, следует помнить что размещение файлов является чисто логической организацией и не влияет на функциональность метаданных ядра, поскольку все каталоги cfg, features, patches
и
ktypes
содержат
те или иные свойства
.

Пути в файлах метаданных ядра указываются относительно каталога base, который указан в переменной FILESEXTRAPATHS
(если
метаданные созданы в
recipe-space) или является верхним уровнем yocto-kernel-cache, если метаданные созданы вне recipe-space (см. параграф 3.4.2. Метаданные вне recipe-space).

3.3.1. Конфигурация

Простейшим элементом метаданных ядра являются параметры конфигурации. Это свойство включает один или несколько параметров конфигурации ядра в файлах фрагментов конфигурации (.cfg) и файлах .scc с описаниями.

В качестве примера рассмотрим фрагмент симметричной многопроцессорной обработки (SMP) в ядре linux-yocto-4.12,
определенный
за пределами пространства задания
(т. еyocto-kernel-cache). Эти метаданные включают 2 файла — smp.scc и smp.cfg. Эти файлы можно найти в каталоге cfg ветви yocto-4.12 репозитория Git yocto-kernel-cache.

     cfg/smp.scc:
        define KFEATURE_DESCRIPTION "Enable SMP for 32 bit builds"
        define KFEATURE_COMPATIBILITY all

        kconf hardware smp.cfg

     cfg/smp.cfg:
        CONFIG_SMP=y
        CONFIG_SCHED_SMT=y
        # Increase default NR_CPUS from 8 to 64 so that platform with
        # more than 8 processors can be all activated at boot time
        CONFIG_NR_CPUS=64
        # The following is needed when setting NR_CPUS to something
        # greater than 8 on x86 architectures, it should be automatically
        # disregarded by Kconfig when using a different arch
        CONFIG_X86_BIGSMP=y            

Базовая информация о фрагментах конфигурации приведена в параграфе 2.6.3. Создание фрагментов конфигурации.

В файле smp.scc оператор KFEATURE_DESCRIPTION задает краткое описание фрагмента, используемое инструментами верхнего уровня. Команда kconf в этом файле включает реальный фрагмент конфигурации, а ключевое слово hardware указывает, что фрагмент включает оборудование в отличие от базовой политики, использующей ключевое слово non-hardware. Это различие помогает инструментам проверки конфигурации, которые будут выдавать предупреждение, если аппаратный фрагмент переопределяет правило, установленное фрагментом non-hardware.

Файл описания может включать множество операторов kconf (по одному на фрагмент).

Как указано в параграфе 2.6.4. Проверка корректности конфигурации, вы можете использовать приведенную ниже команду BitBake для аудита вашей конфигурации.

     $ bitbake linux-yocto -c kernel_configcheck -f

3.3.2. Исправления

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

Типичное исправление включает файл описания и сам patch-файл. Рассмотрим в качестве примера исправления сборки, используемые в ядре linux-yocto-4.12 и определенные за пределами пространства задания (т. е. yocto-kernel-cache). Эти метаданные включают несколько файлов — build.scc и набор файлов *.patch,
которые
можно посмотреть в каталоге
patches/build ветви yocto-4.12 в репозитории Git yocto-kernel-cache.

Ниже приведено содержимое файлов build.scc и modpost-mask-trivial-warnings.patch.

     patches/build/build.scc:
        patch arm-serialize-build-targets.patch
        patch powerpc-serialize-image-targets.patch
        patch kbuild-exclude-meta-directory-from-distclean-processi.patch

        # applied by kgit
        # patch kbuild-add-meta-files-to-the-ignore-li.patch

        patch modpost-mask-trivial-warnings.patch
        patch menuconfig-check-lxdiaglog.sh-Allow-specification-of.patch

     patches/build/modpost-mask-trivial-warnings.patch:
        From bd48931bc142bdd104668f3a062a1f22600aae61 Mon Sep 17 00:00:00 2001
        From: Paul Gortmaker <paul.gortmaker@windriver.com>
        Date: Sun, 25 Jan 2009 17:58:09 -0500
        Subject: [PATCH] modpost: mask trivial warnings

        Newer HOSTCC will complain about various stdio fcns because
                          .
                          .
                          .
                char *dump_write = NULL, *files_source = NULL;
                int opt;
        --
        2.10.1

Файл описания может включать множество операторов patch, каждый из которых относится к одному файлу исправлений .patch. В приведенном примере файл build.scc содержит 5 операторов patch для пяти файлов исправления в каталоге.

Вы можете создавать файлы .patch с помощью команды diff
-Nurp
или git
format-patch
. Описание работы с файлами исправлений приведено в параграфах 2.4. Использование devtool для применения изменений к ядру и 2.5. Традиционные методы внесения изменений в ядро.

3.3.3. Свойства

Свойства являются комплексным типом метаданных ядра и содержат фрагменты конфигурации и исправления, а также могут включать другие файлы описания свойств. В качестве примера рассмотрим приведенный ниже файл.

features/myfeature.scc define KFEATURE_DESCRIPTION "Enable myfeature"
patch 0001-myfeature-core.patch patch 0002-myfeature-interface.patch
include cfg/myfeature_dependency.scc kconf non-hardware myfeature.cfg

Здесь показано использование команд patch и kconf,
а
также включение дополнительного файла
описания возможностей с помощью команды
include.

Обычно свойства менее детализированы по сравнению с фрагментами конфигурации и с большей вероятностью, чем фрагменты и исправления, описывают то, что вы захотите задать в переменной KERNEL_FEATURES задания для ядра Linux (см. параграф 3.2. Использование метаданных ядра в задании).

3.3.4. Типы ядер

Тип ядра определяет политику верхнего уровня путем объединения не связанных с оборудованием фрагментов конфигурации с исправлениями (patch), которые следует применить для сборки ядра Linux с определенными свойствами (например, для работы в реальном масштабе времени). Синтаксически типы ядра не отличаются от свойств, описанных в параграфе 3.3.3. Свойства. Переменная LINUX_KERNEL_TYPE в задании для ядра указывает тип ядра. Например, в задании linux-yocto_4.12.bb из каталога poky/meta/recipes-kernel/linux
директива
require [9] включает файл poky/meta/recipes-kernel/linux/linux-yocto.inc, который задает используемый по умолчанию тип ядра.

     LINUX_KERNEL_TYPE ??= "standard"

Другим примером будет ядро для работы в реальном масштабе времени (linux-yocto-rt_4.12.bb), задание для которого непосредственно устанавливает тип, как показано ниже.

     LINUX_KERNEL_TYPE = "preempt-rt"

Задания для ядра можно найти в каталоге meta/recipes-kernel/linux каталога исходных кодов (например, poky/meta/recipes-kernel/linux/linux-yocto_4.12.bb). Работа с метаданными в заданиях описана в параграфе 3.2. Использование метаданных ядра в задании.

Для ядер Linux Yocto поддерживается три типа — standard, tiny и preempt-rt.

standard

Включает базовые правила заданий для ядра YP linux-yocto, включающие наряду с прочим файловые системы, сетевые опции, базовые функции ядра, а также опции отладки и трассировки.

preempt-rt

Задает использование правок PREEMPT_RT и параметров конфигурации, требуемых для работы ядра в реальном масштабе времени. Этот тип наследует свойства типа standard.

tiny

Задает минимальную конфигурацию для создания очень компактного ядра Linux. Тип tiny не зависит от конфигурации standard. В настоящее время тип tiny не вносит изменений в исходный код, но в будущем это возможно.

Для любого типа ядра метаданные определяются в файле .scc (например, standard.scc). Ниже приведена часть файла standard.scc file из каталога ktypes/standard в репозитории Git yocto-kernel-cache.

     # Include this kernel type fragment to get the standard features and
     # configuration values.

     # Note: if only the features are desired, but not the configuration
     #       then this should be included as:
     #             include ktypes/standard/standard.scc nocfg
     #       if no chained configuration is desired, include it as:
     #             include ktypes/standard/standard.scc nocfg inherit


     include ktypes/base/base.scc
     branch standard

     kconf non-hardware standard.cfg

     include features/kgdb/kgdb.scc
                .
                .
                .

     include cfg/net/ip6_nf.scc
     include cfg/net/bridge.scc

     include cfg/systemd.scc

     include features/rfkill/rfkill.scc            

Как и другие файлы .scc, определение типа ядра может включать другие файлы .scc с помощью команд include. Эти определения могут напрямую «затягивать» фрагменты конфигурации и patch-файлы с помощью команд kconf и patch.

Не обязательно создавать файл .scc для типа ядра. Файл BSP может неявно указывать тип ядра с помощью строки KTYPE
myktype
(см.
параграф 3.3.5. Описания BSP)
.

3.3.5. Описания BSP

Описания BSP (файлы *.scc) комбинируют типы ядер с аппаратно-зависимыми функциями. Связанные с оборудованием метаданные обычно определяются независимо на уровне BSP, а затем объединяются с каждым поддерживаемым типом ядра.

Для BSP, поддерживаемых в YP, файлы описаний BSP размещаются в каталоге bsp репозитория yocto-kernel-cache (раздел Yocto Linux Kernel по ссылке Yocto Project Source Repositories).

Далее приведен обзор структуры описаний BSP и концепций агрегирования, а также пример использования BSP в YP (BeagleBone Board). Полная информация об иерархии файлов уровня BSP дана в [5].

3.3.5.1. Обзор

Рассмотрим файлы описания корневого уровня BSP для платы BeagleBone. Структура и имена файлов соответствуют упомянутым выше рекомендациям. В соответствии с соглашением об именовании имя определяется как

bsp_root_name-kernel_type.scc

Ниже указаны два примера имен файлов корневого уровня BSP для BeagleBone Board BSP, поддерживаемых YP.

     beaglebone-standard.scc
     beaglebone-preempt-rt.scc                

Каждый из файлов использует корневое имя BSP (beaglebone), за которым следует тип ядра.

Рассмотрим файл beaglebone-standard.scc

     define KMACHINE beaglebone
     define KTYPE standard
     define KARCH arm

     include ktypes/standard/standard.scc
     branch beaglebone

     include beaglebone.scc

     # default policy for standard kernels
     include features/latencytop/latencytop.scc
     include features/profiling/profiling.scc                

Каждому файлу описания верхнего уровня BSP следует определять переменные KMACHINE, KTYPE
и
KARCH,
которые
позволяют системе сборки
OE идентифицировать описание как соответствующее критериям, установленным заданием. В этом примере поддерживается машина beaglebone с ядром standard для архитектуры arm.

Следует принимать во внимание отсутствие жесткой привязки переменной KTYPE к файлу описания типа ядра. Если тип ядра не указан в метаданных ядра, как описано здесь, нужно убедиться в совпадении значений переменной LINUX_KERNEL_TYPE в задании для ядра и переменной KTYPE в описании BSP.

Чтобы отделить политику ядра от аппаратной конфигурации, указывается тип ядра (ktype), такой как standard. В предыдущем примере это сделано с помощью строки, приведенной ниже

     include ktypes/standard/standard.scc

Файл объединяет все фрагменты конфигурации, patch-файлы и возможности, которые определяют вашу стандартную политику ядра (см. параграф 3.3.4. Типы ядер).

Для объединения базовых конфигураций и возможностей, относящихся к ядру для mybsp, служит строка

include mybsp.scc 

В примере BeagleBone используется строка

     include beaglebone.scc

Информация о разбиении полного файла .config на фрагменты конфигурации приведена в параграфе 2.6.3. Создание фрагментов конфигурации.

Если конфигурация, связанная с оборудованием, отсутствует в файле *.scc, ее можно включить с помощью строки

kconf hardware mybsp-extra.cfg

Пример BeagleBone не включает эти типы конфигурации, однако для 32-битовой платы Malta (mti-malta32)они включены в файл mti-malta32-le-standard.scc, приведенный ниже.

     define KMACHINE mti-malta32-le
     define KMACHINE qemumipsel
     define KTYPE standard
     define KARCH mips

     include ktypes/standard/standard.scc
     branch mti-malta32

     include mti-malta32.scc
     kconf hardware mti-malta32-le.cfg                
3.3.5.2. Пример

Реальные примеры в основном сложнее. Подобно другим файлам .scc, описания BSP могут объединять возможности. Рассмотрим определение Minnow BSP из ветви linux-yocto-4.4 в yocto-kernel-cache (yocto-kernel-cache/bsp/minnow/minnow.scc)

Хотя Minnow Board BSP не применяется, метаданные сохранены и будут служить здесь в качестве примера.

         include cfg/x86.scc
         include features/eg20t/eg20t.scc
         include cfg/dmaengine.scc
         include features/power/intel.scc
         include cfg/efi.scc
         include features/usb/ehci-hcd.scc
         include features/usb/ohci-hcd.scc
         include features/usb/usb-gadgets.scc
         include features/usb/touchscreen-composite.scc
         include cfg/timer/hpet.scc
         include features/leds/leds.scc
         include features/spi/spidev.scc
         include features/i2c/i2cdev.scc
         include features/mei/mei-txe.scc

         # Earlyprintk and port debug requires 8250
         kconf hardware cfg/8250.cfg

         kconf hardware minnow.cfg
         kconf hardware minnow-dev.cfg                

Файл описания minnow.scc включает фрагмент аппаратной конфигурации (minnow.cfg) для Minnow BSP, а также несколько фрагментов конфигурации общего назначения и возможности, включающее оборудование на плате. Этот файл описания minnow.scc включается в каждый из трех файлов описаний minnow для поддерживаемых типов ядра (standard, preempt-rt, tiny). Рассмотрим описание minnow для ядра типа standard (файл minnow-standard.scc).

         define KMACHINE minnow
         define KTYPE standard
         define KARCH i386

         include ktypes/standard

         include minnow.scc

         # Extra minnow configs above the minimal defined in minnow.scc
         include cfg/efi-ext.scc
         include features/media/media-all.scc
         include features/sound/snd_hda_intel.scc

         # The following should really be in standard.scc
         # USB live-image support
         include cfg/usb-mass-storage.scc
         include cfg/boot-live.scc

         # Basic profiling
         include features/latencytop/latencytop.scc
         include features/profiling/profiling.scc

         # Requested drivers that don't have an existing scc
         kconf hardware minnow-drivers-extra.cfg                

Команда include включает описание minnow.scc,
которое
определяет оборудование
BSP, общее для всех типов ядра. Это существенно снижает дублирование.

Рассмотрим описание minnow для ядра типа «tiny (minnow-tiny.scc)

        define KMACHINE minnow
        define KTYPE tiny
        define KARCH i386

        include ktypes/tiny

        include minnow.scc                

Легко видеть, что это описание существенно меньше и фактически включает лишь минимальные правила, заданные типом ядра tiny и зависящую от оборудования конфигурацию, требуемую для загрузки машины, вместе с базовой функциональностью системы, определенной в файле описания minnow» description file.

Еще раз отметим 3 важных переменных — KMACHINE, KTYPE, KARCH. Из них лишь KTYPE меняется для типа tiny.

3.4. Размещение метаданных ядра

Метаданные ядра всегда размещаются за пределами дерева кодов, указанного в задании для ядра (recipe-space), или вне задания. Выбор метаданных зависит от задачи и способа ее выполнения. Синтаксис метаданных не зависит от места их определения.

Если вы не имеете опыта работы с ядром Linux и хотите лишь применить конфигурацию и возможно небольшие изменения, подготовленные другими людьми, рекомендуется использовать метод recipe-space. Он также хорошо подходит для случаев работы с неконтролируемыми исходными кодами ядра или просто не хотите поддерживать свой репозиторий Git для ядра Linux. Информация об определении метаданных в recipe-space частично приведена в параграфе 2.3. Изменение существующего задания.

Если вы активно занимаетесь разработками для ядра и уже поддерживаете свой репозиторий Git, может оказаться более удобным размещение метаданных за пределами recipe-space. Такой подход позволяет повысить эффективность интерактивной разработки для ядра Linux за пределами среды BitBake.

3.4.1. Метаданные в recipe-space

При сохранении метаданных ядра в recipe-space они размещаются в иерархии каталогов под FILESEXTRAPATHS. Для задания linux-yocto или задания, созданного на основе oe-core/meta-skeleton/recipes-kernel/linux/linux-yocto-custom.bb переменная FILESEXTRAPATHS обычно имеет значение ${THISDIR}/${PN} (см. параграф 2.3. Изменение существующего задания).

Ниже представлен пример, показывающий тривиальное дерево метаданных ядра в recipe-space внутри уровня BSP.

meta-my_bsp_layer/ `-- recipes-kernel `-- linux `-- linux-yocto |-- bsp-standard.scc |-- bsp.cfg `-- standard.cfg

Когда метаданные хранятся в recipe-space, нужно предпринять определенные действия по обеспечению BitBake информацией, которая нужна для извлечения метаданных. Для этого нужно указать файлы .scc в переменной SRC_URI. BitBake проанализирует их и извлечет файлы, указанные в .scc командами include, patch
или kconf. Поэтому нужно менять значение PR в задании при изменении содержимого файлов, указанных в SRC_URI.

Если описание BSP находится в recipe-space, нельзя просто изменить список файлов *.scc в операторе SRC_URI. Нужно использовать приведенную ниже форму из файла добавления для ядра.

SRC_URI_append_myplatform = " \ file://myplatform;type=kmeta;destsuffix=myplatform \ "  

3.4.2. Метаданные вне recipe-space

При сохранении за пределами recipe-space метаданные ядра размещаются в отдельном репозитории. Система сборки OE добавляет метаданные в сборку как репозиторий type=kmeta в переменной SRC_URI. В качестве примера рассмотрим оператор SRC_URI из задания для ядра linux-yocto_4.12.bb.

SRC_URI = "git://git.yoctoproject.org/linux-yocto-4.12.git;name=machine;branch=${KBRANCH}; \
git://git.yoctoproject.org/yocto-kernel-cache;type=kmeta;name=meta;branch=yocto-4.12;destsuffix=${KMETA}"            

В этом
контексте
${KMETA}
просто
указывает каталог, в который сборщик
Git помещает метаданные. Э/то не отличается от поведения, заданного оператором SRC_URI для множества репозиториев в задании (см. выше).

Можно хранить метаданные ядра в кэше ядра, который является каталогом с фрагментами конфигурации. Как и для других метаданных за пределами recipe-space, нужно просто использовать оператор SRC_URI с атрибутом type=kmeta, что делает метаданные ядра доступными при настройке конфигурации.

При изменении метаданных нужно обновлять операторы SRCREV в задании для ядра. В частности, нужно обновлять переменную SRCREV_meta в соответствии с фиксацией (commit) в используемой ветви KMETA. Изменение данных в этих ветвях без соответствующего обновления операторов SRCREV приведет к использованию при сборке старых фиксаций.

3.5. Организация исходных кодов

Многие задания, основанные на linux-yocto-custom.bb используют исходные коды ядра Linux с единственной ветвью master. Этот тип структуры репозитория отлично подходит для разработок, поддерживающих одну машину и архитектуру. Однако при работе с разными платами или архитектурой эффективней использовать репозиторий исходных кодов с множеством ветвей. Предположим, например, что вам нужна серия исправления для загрузки одной платы. Иногда эти исправления находятся в стадии разработки или в корне ошибочны, но все же нужны для определенных плат. В таких ситуациях вы скорей всего не захотите включать эти исправления в каждую сборку ядра (т. е. в ветвь master). Именно для таких ситуация применяется ветвление в репозиториях Git для ядра Linux.

Существуют стратегии организации репозитория, максимизирующие многократное использование кода, устраняющие избыточность и логически упорядочивающие внесенные изменения. В этом параграфе представлена стратегия для нескольких случаев.

  • Инкапсуляция исправлений в описание свойства и включение patch-файлов только в описания BSP соответствующих плат.
  • Создание ветви для машины в вашем репозитории кодов и применение исправлений лишь к этой ветви.
  • Создание ветви для возможности и при необходимости слияние этой ветви с BSP.

Выбор подхода полностью определяется вами с учетом вашей модели разработки.

3.5.1. Инкапсуляция исправлений

Если вы многократно используете patch-файлы из внешнего дерева и не создаете своих исправлений, инкапсуляция может быть подходящим решением. В этом варианте не нужно создавать ветвей в репозитории исходных кодов. Просто берутся нужные статические patch-файлы и инкапсулируются в описание свойства, которое включается в описание BSP, как указано в параграфе 3.3.5. Описания BSP.

3.5.2. Ветви для машин

При работе с несколькими машинами и разной архитектурой или активной поддержке определенных плат более эффективно создавать в репозитории ветви для конкретных машин. Это позволяет сохранять для общего дерева кодов ветвь master, а относящиеся к конкретной машине свойства хранить в ветви для этой машины. Такой метод освобождает от необходимости постоянно встраивать ваши исправления в свойство.

При создании новой ветви можно организовать метаданные для использования ветви разными способами. В задании можно указать новую ветвь как KBRANCH для использования с платой

     KBRANCH = "mynewbranch"

Другой метод использует команду branch в описании BSP.

     mybsp.scc:
        define KMACHINE mybsp
        define KTYPE standard
        define KARCH i386
        include standard.scc

        branch mynewbranch

        include mybsp-hw.scc            

При наличии множества ветвей можно применять структуру, аналогичную используемой в репозиториях Yocto Linux Kernel Git

common/kernel_type/machine

Если вы используете два типа ядер (например, standard и small), три машины и общий корень mydir, ветви вашего репозитория могут иметь вид

     mydir/base
     mydir/standard/base
     mydir/standard/machine_a
     mydir/standard/machine_b
     mydir/standard/machine_c
     mydir/small/base
     mydir/small/machine_a            

Такая организация позволяет ясно видеть связи между ветвями. В приведенном примере mydir/standard/machine_a включает все из mydir/base mydir/standard/base. Ветви standard и small добавляют исходные коды, относящиеся к этим ветвям и по той или иной причине не подходящие для других ветвей.

Ветвь base является деталью внутреннего управления Git в своей файловой системе, не позволяя использовать mydir/standard и mydir/standard/machine_a,
поскольку
это будет создавать файл и каталог с
именем
standard.

3.5.3. Ветви для свойств

При активной разработке новых свойств может оказаться более эффективным ветвление по свойствам, а не наборам исправлений, которые нужно регулярно обновлять. Инструменты для ядер YP Linux позволяют делать это с помощью команды git
merge
.

Для слияния ветви по свойству с BSP нужно поместить команду git
merge
после каждой команды branch.

     mybsp.scc:
        define KMACHINE mybsp
        define KTYPE standard
        define KARCH i386
        include standard.scc

        branch mynewbranch
        git merge myfeature

        include mybsp-hw.scc            

3.6. Команды в файлах описаний

Здесь приведен краткий обзор команд, которые можно использовать в файлах описаний (.scc)

branch [ref]

Создает новую ветвь (обычно ${KTYPE}), используя выбранную или указанную параметром ref ветвь.

define

Определяет переменные (такие как KMACHINE, KTYPE, KARCH, KFEATURE_DESCRIPTION).

include SCC_FILE

Включает файл SCC в текущий файл с анализом как при встраивании (inline).

kconf [hardware|non-hardware] CFG_FILE

Помещает фрагмент конфигурации в очередь для слияния в финальный файл конфигурации ядра Linux (.config).

git merge GIT_BRANCH

Сливает ветвь свойства с текущей ветвью.

patch PATCH_FILE

Применяет исправление (patch) к текущей ветви Git.

В [1] scc считается сокращением от Series Configuration Control (управление последовательностью конфигураций), но в текущей реализации это уже частично утратило смысл и файлы .scc стали файлами описаний.

Приложение A. Дополнительные вопросы

A.1. Разработка и поддержка YP Kernel

Ядра в YP (ядра Yocto Linux), как и другие ядра, имеют в своей основе исходные коды выпусков ядра Linux с сайта http://www.kernel.org. В начале цикла создания новой версии ядра Linux команда YP выбирает версию ядра Linux с учетом времени выпуска, прогнозируемого срока выпуска финальной версии и функциональных требований YP. Обычно выбирается ядро на финальной стадии разработки сообществом Linux. Иными словами, это предварительный выпуск (rc), который еще не стал финальным. Но на заключительных этапах разработки команда знает о близости окончательно выпуска, который наступает на ранней стадии разработки YP.

Это позволяет команде YP выпускать современные версии ядер Yocto Linux, соответствующие стабильным выпускам базового ядра Linux.

Как отмечено выше, основным источником для ядер Yocto Linux являются ядра с kernel.org. В дополнение к этому ядра Yocto Linux включают набор важных основных (mainline) и не основных (когда нет вариантов) разработок, BSP и специальных возможностей. Это обеспечивает выпуск ядер YP Linux, соответствующих потребностям разработчиков встраиваемых систем для целевых платформ.

Web-интерфейс для доступа к ядрам Yocto Linux в репозиториях исходных кодов доступен по ссылке http://git.yoctoproject.org. В этом интерфейсе вы увидите слева группу репозиториев Git под рубрикой Yocto Linux Kernel, в которой доступно несколько выпусков ядра Linux Yocto.

linux-yocto-4.1

Стабильное ядро YP для использования с YP 2.0 на основе ядра Linux 4.1.

linux-yocto-4.4

Стабильное ядро YP для использования с YP 2.1 на основе ядра Linux 4.4.

linux-yocto-4.6

Временное ядро, не привязанное к выпуску YP.

linux-yocto-4.8

Стабильное ядро YP для использования с YP 2.2.

linux-yocto-4.9

Стабильное ядро YP для использования с YP 2.3 на основе ядра Linux 4.9.

linux-yocto-4.10

Стабильное ядро YP для использования с YP 2.3 на основе ядра Linux 4.10.

linux-yocto-4.12

Стабильное ядро YP для использования с YP 2.4 на основе ядра 4.12.

yocto-kernel-cache

Исправления (patch) и конфигурационные файлы для дерева linux-yocto (Глава 3. Работа с расширенными метаданными (yocto-kernel-cache).

linux-yocto-dev

Находящееся в разработке ядро для последнего доступного rc.

Инициатива долгосрочной поддержки LTSI7 для ядер Yocto Linux включает:

  • для YP 1.7, 1.8, 2.0 — linux-yocto-3.14;

  • для YP 2.1, 2.2, 2.3 — linux-yocto-4.1;

  • для YP 2.4 — linux-yocto-4.9.

  • linux-yocto-4.4 является ядром LTS8.

Как только ядро Yocto Linux выпущено официально, команда YP начинает следующий цикл разработки или цикл uprev9, сохраняя поддержку выпущенного ядра. Важно подчеркнуть, что наиболее устойчивый и стабильный способ включения потока будущей разработки выполняется через процесс uprev. Перенос сотен исправлений и второстепенных возможностей из разных версий ядра не обеспечивает устойчивость и может стать угрозой качеству.

В цикле uprev команда YP использует текущий анализ разработки ядра Linux, поддержки BSP и время выпуска для выбора наиболее подходящей версии с kernel.org,
на
основе которой будет создаваться
последующая версия ядра
Yocto Linux. Команда постоянно отслеживает разработку ядра сообществом Linux для фиксации интересных возможностей. Рассматривается также перенос существенных возможностей в прежние версии, если это обеспечит преимущество. Запросы пользователей и сообщества также могут инициировать перенос возможностей в прежние версии или добавление функциональности в базовое ядро YP в цикле uprev.

Вообще говоря, каждое новое ядро вносит новые функции и добавляет новые ошибки. Эти свойства разработки ядер Linux контролируются стратегией разработки ядер команды YP. Политика команды заключается в том, чтобы не переносить маловажные свойства в прошлые выпуски ядер Yocto Linux. Рассматривается лишь возможность переноса существенных технологических прорывов и только после их полного анализа. Причина этого заключается в том, что перенос малозначимых возможностей в прошлые выпуски может приводить к несоответствиям, несовместимости и коварным ошибкам.

Описанная здесь политика позволяет сделать ядро Yocto Linux передовым и стабильным, объединяющим имеющиеся возможности ядра Linux с важными новыми функциями. Перенос перспективных функций ядра Linux в ядро Yocto Linux доступный в YP, можно рассматривать как микро-uprev. Множество таких переносов создает версию ядра Yocto Linux, сочетающую важные новые функции с разработками BSP. Такое ядро Yocto Linux дает представление о новых возможностях и позволяет выполнять целевые тесты, предотвращающие сюрпризы при выборе следующего основного uprev. Качество таких ядер Yocto Linux повышается и они служат основой для разработок.

A.2. Архитектура Yocto Linux Kernel и стратегия ветвления

Как было отмечено выше, основной целью YP является предоставление разработчикам ядра с четкой и непрерывной историей, видимой пользователям. Используемая архитектура и механизмы (в частности, стратегия ветвления) обеспечивают достижение этой цели аналогично разработке ядра Linux сообществом kernel.org.

Ядро Yocto Linux можно рассматривать как базовое ядро Linux с добавлением логически структурированных функций, которые помечены и организованы с помощью стратегии ветвления, реализованной командой YP на основе SCM10 Git.

  • Git является очевидным выбором SCM с учетом организационных и структурных потребностей Yocto Linux, описанных здесь. Git не только служит SCM для разработки ядра Linux на kernel.org, но и продолжает набирать популярность и поддержку в разных проектах, системах и методах управления.

  • Документация для Git доступна на сайте http://git-scm.com/documentation. Вводная информация о Git в контексте YP представлена в разделе Git [7], где приведен обзор и описан минимальный набор команд Git для работы с YP.

Используя теги и ветви Git, команда YP организует ветвление ядра в точках, где функциональность перестает быть общей и должна быть отделена. Например, связанные с платой несовместимости могут требовать других функций с их выделением в особую ветвь. Аналогичный подход применяется и для ветвления по свойствам ядра.

Эта древовидная архитектура приводит к созданию структуры, организованной по конкретной функциональности, типам или подтипам ядер. В результате пользователь может видеть добавленные свойства и связанные с ними фиксации (commit). Кроме того, пользователь может видеть историю изменения базового ядра Linux.

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

Команда YP старается размещать свойства в дереве так, чтобы их можно было применять для всех возможных плат и типов ядра. Однако в процессе разработки или при объединении крупных функций (свойств) такой подход возможен не всегда. В таких случаях для объединения свойств применяется ветвление.

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

Хотя эта стратегия может приводить к росту числа ветвей дерева, важно понимать, что с точки зрения разработчика есть линейный путь от базового ядра kernel.org
через
выбор группы возможностей к связанным
с
BSP фиксациям (commit). Этим путем для разработчика является ветвь master в терминах Git. Разработчику не нужно даже знать о наличии иных ветвей. Эти ветви имеют ценность для тех, кто захочет их исследовать. Например, сравнение двух BSP на уровне фиксации или построчных различий в коде становится тривиальной
операцией
.


Рисунок 1. Ветвление в ядре Yocto Linux.


На рисунке Kernel.org Branch Point указывает конкретную точку (выпуск ядра Linux), где создается ядро Yocto Linux. От этой точки в дереве организуются и помечаются свойства и различия.

Ветвь Yocto Project Baseline Kernel содержит общие для всех типов ядра и BSP функции, организованные в форме дерева. Такое размещение основных свойств в дереве означает отсутствие дублирования свойств в разных ветвях.

Ветви Yocto Project Baseline Kernel представляют конкретную функциональность для отдельных BSP, а также ядра для работы в реальном масштабе времени. На рисунке показаны ветви для трех BSP и ветвь real-time, каждая из которых представляет уникальную функциональность.

В показанной структуре ветвь Real-time (rt) Kernel имеет свойства, которые относятся ко всем ядрам real-time Yocto Linux, и дополнительные ветви для отдельных BSP в таких ядрах.

Древовидная структура представляет разработчику четкую последовательность маркеров (ветвей) для всех практических задач.

Рисунок служит лишь для иллюстрации и на нем показаны далеко не все ядра Yocto Linux. Следует также учитывать. Что эта структура представляет репозитории исходных кодов YP [7], которые загружаются при сборке или организуются сборочным хостом до начала сборки путем клонирования репозитория Git или загрузки и распаковки архива.

Работа с ядром, структурированным как дерево, подтверждена практикой. В частности, представленное ядро следует считать «восходящим источником» и рассматривать как последовательность документированных изменений (фиксаций). Эти изменения представляют разработку и стабилизацию, выполненную командой YP.

Поскольку изменения фиксируются лишь для значимых точек выпуска в жизненном цикле продукции, разработчики могут использовать ветвь, созданную из последней соответствующей фиксации (commit) в представленном ядре YP Linux. Как отмечено выше, структура понятна разработчикам, поскольку ядро дерева сохраняет состояние после клонирования и сборки.

A.3. Иерархия файлов для сборки ядра

Восходящее хранилище доступного исходного кода ядра и представление кода в вашей системе разработки — это разные сущности. Концептуально можно представлять репозиторий исходных кодов ядра как все исходные файлы, требуемые для всех поддерживаемых ядер Yocto Linux. Как разработчику, вам нужны исходные коды для ядра, с которым вы работаете, поэтому они нужны на сборочном хосте. Получить исходные коды на сборочный хост можно несколькими способами.

  • Доступ с использованием devtool из состава YP является предпочтительным методом работы с ядром (см. параграф 1.2. Рабочий процесс изменения ядра).

  • Клонированный репозиторий. При постоянной работе с ядром имеет смысл организовать локальный репозиторий Git для ядра Yocto Linux. Информация о клонировании приведена в параграфе 2.1. Подготовка сборочного хоста для работы с ядром.

  • Временные исходные файлы из сборки. Если нужно просто применить некоторые изменения к ядру с использованием обычных процессов BitBake (т. е. без devtool), можно работать с временными исходными файлами, которые были загружены и использовались при сборке ядра.

Временные файлы исходных кодов, полученные при сборке ядра с помощью BitBake, организованы в определенную иерархию. При сборке ядра на вашей системе все нужные файлы извлекаются из репозиториев, указанных переменной SRC_URI [1], и собираются во временной рабочей области для создания ядра. Таким образом, организуется локальное дерево исходных кодов для создаваемого образа ядра.

На рисунке 2 показана временная файловая структура, создаваемая на сборочном хосте при создании ядра с использованием Bitbake. Этот сборочный каталог содержит все файлы, нужные для сборки.


Рисунок 2. Структура файлов временного репозитория.


Дополнительная информация об архитектуре ядра YP и стратегии ветвления приведена в приложении A.2. Архитектура Yocto Linux Kernel и стратегия ветвления, а в параграфах 2.4. Использование devtool для применения изменений к ядру и 2.5. Традиционные методы внесения изменений в ядро приведены примеры внесения изменений в ядро.

A.4. Указание свойств ядра для фазы проверки конфигурации

В этом параграфе частично описана фаза аудита ядра, которую большинство разработчиков могут пропустить. Общая информация о настройке конфигурации ядра приведена в параграфе 2.6. Настройка конфигурации ядра.

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

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

Для разделения «аппаратных» и «неаппаратных» опций метаданные ядра в yocto-kernel-cache включают файлы с классификацией отдельных опций или их групп. Рассмотрим в качестве примера yocto-kernel-cache с файлами

     yocto-kernel-cache/features/drm-psb/hardware.cfg
     yocto-kernel-cache/features/kgdb/hardware.cfg
     yocto-kernel-cache/ktypes/base/hardware.cfg
     yocto-kernel-cache/bsp/mti-malta32/hardware.cfg
     yocto-kernel-cache/bsp/fsl-mpc8315e-rdb/hardware.cfg
     yocto-kernel-cache/bsp/qemu-ppc32/hardware.cfg
     yocto-kernel-cache/bsp/qemuarma9/hardware.cfg
     yocto-kernel-cache/bsp/mti-malta64/hardware.cfg
     yocto-kernel-cache/bsp/arm-versatile-926ejs/hardware.cfg
     yocto-kernel-cache/bsp/common-pc/hardware.cfg
     yocto-kernel-cache/bsp/common-pc-64/hardware.cfg
     yocto-kernel-cache/features/rfkill/non-hardware.cfg
     yocto-kernel-cache/ktypes/base/non-hardware.cfg
     yocto-kernel-cache/features/aufs/non-hardware.kcf
     yocto-kernel-cache/features/ocf/non-hardware.kcf
     yocto-kernel-cache/ktypes/base/non-hardware.kcf
     yocto-kernel-cache/ktypes/base/hardware.kcf
     yocto-kernel-cache/bsp/qemu-ppc32/hardware.kcf            

Ниже приведены краткие разъяснения для некоторых из этих файлов.

  • hardware.kcf задает список файлов Kconfig, включающих только аппаратные опции.

  • non-hardware.kcf
    задает
    список файлов
    Kconfig,
    включающих
    только неаппаратные опции
    .

  • hardware.cfg
    задает
    список опций ядра
    CONFIG_ options, которые являются аппаратными независимо от указания в той или иной категории файлов Kconfig (например, hardware.kcf или non-hardware.kcf).

  • non-hardware.cfg
    задает
    список опций ядра
    CONFIG_
    options,
    которые
    не являются аппаратными независимо от
    указания в той или иной категории файлов
    Kconfig
    (
    например,
    hardware.kcf
    или
    non-hardware.kcf).

Ниже приведен пример использования файла kernel-cache/bsp/mti-malta32/hardware.cfg:

     CONFIG_SERIAL_8250
     CONFIG_SERIAL_8250_CONSOLE
     CONFIG_SERIAL_8250_NR_UARTS
     CONFIG_SERIAL_8250_PCI
     CONFIG_SERIAL_CORE
     CONFIG_SERIAL_CORE_CONSOLE
     CONFIG_VGA_ARB            

При аудите конфигурации ядра упомянутые файлы (они должны иметь указанные здесь имена) будут автоматически найдены и использованы в качестве входных данных для сравнения с окончательным файлом .config.

В пользовательском репозитории метаданных ядра или recipe-space могут применяться такие же имена файлов для классификации опций как аппаратных или неаппаратных, чтобы система сборки OE не выдавала предупреждений или ошибок при отсутствии опции в файле .config.

Приложение B. Поддержка ядра

B.1. Организация дерева

Здесь описано создание репозиториев исходного кода ядер YP, выполняемое командой YP. Эти репозитории можно найти в рубрике Yocto Linux Kernel на сайте http://git.yoctoproject.org и они включаются в выпуски YP. Репозитории создаются путем компиляции и выполнения набора описаний свойств для каждого BSP и свойства в проекте. Эти описания свойств указывают все требуемые исправления (patch), конфигурации, ветви, теги и свойства для ядра Yocto Linux. Таким образом, создается репозиторий (дерево) ядра YP Linux и сопровождающие его метаданные в yocto-kernel-cache.

Наличие этих репозиториев позволяет получить доступ и клонировать нужный репозиторий ядра YP Linux, а затем использовать его для сборки своих конфигураций.

Файлы, используемые для описания всех действительных свойств и BSP ядра YP Linux в любом клоне репозитория YP Linux и деревьях Git yocto-kernel-cache. Например, приведенные ниже команды будут клонировать базовый репозиторий ядра YP Linux, созданный на основе ядра версии 4.12 и yocto-kernel-cache, где содержатся метаданные.

     $ git clone git://git.yoctoproject.org/linux-yocto-4.12
     $ git clone git://git.yoctoproject.org/linux-kernel-cache            

Дополнительная информация о создании локального репозитория Git с файлами ядра YP Linux приведена в параграфе 2.1. Подготовка сборочного хоста для работы с ядром.

После клонирования репозитория Git и кэша метаданных на локальную машину можно просмотреть все доступные ветви репозитория с помощью команды

     $ git branch -a

Выбор ветви позволяет работать с определенным ядром Yocto Linux. Например, приведенные ниже команды выбирают ветвь standard/beagleboard из репозитория Yocto Linux и ветвь yocto-4.12 из yocto-kernel-cache.

     $ cd ~/linux-yocto-4.12
     $ git checkout -b my-kernel-4.12 remotes/origin/standard/beagleboard
     $ cd ~/linux-kernel-cache
     $ git checkout -b my-4.12-metadata remotes/origin/yocto-4.12            

Ветви репозитория yocto-kernel-cache соответствуют версиям Yocto Linux (например, yocto-4.12, yocto-4.10, yocto-4.9).

После выбора нужно ветви и переключения на нее можно видеть «моментальный снимок» (snapshot) всех файлов исходного кода ядра, используемых для сборки ядра Yocto Linux под конкретную плату. Для просмотра свойств и конфигураций определенного ядра Yocto Linux нужно обратиться к репозиторию yocto-kernel-cache. Как отмечено выше, ветви в yocto-kernel-cache соответствуют версиям ядра Yocto Linux (например, yocto-4.12). Ветви содержат описания в файлах .scc и .cfg.

Следует учитывать. Что просмотр локального репозитория yocto-kernel-cache в части описаний возможностей и patch-файлов не является эффективным способом определения содержимого конкретной ветви. Вместо этого следует использовать Git напрямую для поиска изменений. Это обеспечивает эффективный и гибкий способ просмотра изменений в ядре.

Базовая реконструкция всего дерева ядра предпринимается командой YP только в активном цикле разработки. Создание клона репозитория ядра делает его доступным для сборки и внесения изменений.

Ниже перечислены этапы создания командой YP репозитория (дерева) исходных кодов ядра для сайта http://git.yoctoproject.org с учетом добавления новых свойств верхнего уровня и BSP. Приведенные действия обеспечивают метаданные и создание дерева с новыми возможностями, исправлениями и BSP.

  1. Передача свойства системе сборки OE. Свойство верхнего уровня для ядра передается системе сборки. Обычно этим свойством является BSP для определенного типа ядра.

  2. Размещение свойства. Файл с описанием свойства верхнего уровня отыскивается в одном из каталогов:

    • каталоги кэширования в дереве ядра, расположенные в репозитории yocto-kernel-cache под рубрикой Yocto Linux Kernel в Yocto Project Source Repositories;

    • области, указанные операторами SRC_URI в заданиях ядра.

    Для типичной сборки целью поиска является описание свойства в файле .scc имя которого соответствует приведенному ниже формату (например, beaglebone-standard.scc или beaglebone-preempt-rt.scc).

    bsp_root_name-kernel_type.scc 
  3. Извлечение свойства. Найденное описание свойства извлекается в простой сценарий действий или в имеющийся эквивалентный сценарий, являющийся частью распространяемого ядра.

  4. Добавление дополнительных свойств. С описанию свойства верхнего уровня добавляются дополнительные возможности, которые могут определяться из переменной KERNEL_FEATURES в задании.

  5. Нахождение, извлечение и добавление каждого свойства. Каждое дополнительное свойство отыскивается, извлекается и добавляется в сценарий, как описано в п. 3.

  6. Выполнение сценария для создания файлов .scc и .cfg в нужных каталогах репозитория yocto-kernel-cache. Эти файлы являются описаниями всех ветвей, тегов, исправлений и конфигураций, которые нужно применить к базовому репозиторию Git для завершения создания ветви (сборки) для нового BSP или свойства.

  7. Клонирование базового репозитория и применение действий, указанных в каталогах yocto-kernel-cache, к дереву исходных кодов.

  8. Очистка. Репозитории Git остаются с выбранными ветвями и выполняются все требуемые ветвления, исправления и пометки.

Дерево исходных кодов и кэш готовы для передачи разработчикам, которые будут его клонировать, настраивать и собирать ядра YP для конкретных целевых платформ.

  • Созданный репозиторий yocto-kernel-cache добавляется к ядру, распространяемому с выпуском YP. Все дополнения и данные конфигурации применяются в конце имеющейся ветви. Полный вариант репозитория, доступный по ссылке http://git.yoctoproject.org, включает все поддерживаемые платы и конфигурации.

  • Используемый командой YP метод достаточно гибок и позволяет аккуратно смешивать неизменяемую историю с дополнительными правками, относящимися к конкретному развертыванию. Все дополнения к ядру становятся частями ветвей.

  • Генерируется полное дерево для http://git.yoctoproject.org с помощью перечисленных выше шагов для всех действительных BSP. Конечным результатом является разветвленное дерево с чистой историей, которое образует ядро для данного выпуска. Сценарий, с помощью которого выполняются эти операции (kgit-scc), доступен в репозитории yocto-kernel-tools.

  • Этапы создания полного дерева ядра совпадают с используемыми BitBake этапами сборки образа ядра.

B.2. Стратегия сборки

После клонирования репозитория ядра Yocto Linux и yocto-kernel-cache на свой хост вы можете перейти к компиляции ядра и сборке образа. Однако нужно выполнить ряд предварительных условий, которые проверяются при сборке.

  • Переменная SRC_URI должна указывать репозиторий ядра.

  • Ветвь сборки BSP с метаданными должна присутствовать в репозитории yocto-kernel-cache. Эта ветвь базируется на версии ядра Yocto Linux и включает конфигурации и свойства, собранные в каталоге yocto-kernel-cache/bsp. Например, свойства и конфигурации для платы BeagleBone с ядром linux-yocto_4.12 предполагаются в каталоге

         yocto-kernel-cache/bsp/beaglebone

    Здесь выбрана ветвь yocto-4.12 репозитория yocto-kernel-cache.

Система сборки OE проверяет выполнение этих условий до начала компиляции. Однако имеются и другие способы, такие как начальная загрузка BSP.

Перед сборкой ядра проверяется дерево и настраивается конфигурация ядра путем обработки фрагментов, заданных описаниями свойств в файлах .scc. По мере компиляции свойств связанные с ними фрагменты конфигурации ядра помечаются и записываются в каталоги в порядке компиляции. Фрагменты переносятся, обрабатываются и передаются подсистеме lkc11 как необработанные входные данные в виде файла .config. Система lkc использует внутренние ограничения на основе зависимостей для окончательной обработки информации и создания финального файла .config, используемого при компиляции.

Используя архитектуру платы и другие относящиеся к делу значения, запускается процесс компиляции и создается образ ядра.

Процесс сборки создает дерево сборки, отличное от дерева локального репозитория Git. Это дерево сборки имеет имя включающее ${MACHINE} (метаданные платы — BSP) и тип ядра kernel_type (один из поддерживаемых YP типов, например, standard)

linux-${MACHINE}-kernel_type-build

Поддержка именования в дереве kernel.org обеспечивает эту функциональность по умолчанию.

Это поведение означает, что все созданные файла для определенной машины или BSP будут находиться в каталоге дерева сборки. Эти файлы включают окончательную конфигурацию (.config), все объектные файлы (.o), файлы .a и т. п. Поскольку каждая машина или BSP использует свой каталог сборки [1] в отдельной ветви репозитория Git, вы можете легко переходить от одной сборки к другой.

Приложение C. Вопросы разработки ядра (FAQ)

C.1. Общие вопросы

Ниже рассмотрены решения для некоторых часто возникающих задач.

C.1.1. Установка ядра в rootfs

Образ ядра (например, vmlinuz) создается пакетом kernel-image. Задания для образов зависят от kernel-base. Для управления установкой образа ядра в созданной корневой файловой системе служит переменная RDEPENDS_kernel-base, включающая или не включающая kernel-image.

Использование файла добавления для переопределения метаданных рассмотрено в разделе Using .bbappend Files in Your Layer [4].

C.1.2. Установка конкретных модулей ядра

Модули ядра Linux собираются отдельно. Чтобы обеспечить включение конкретного модуля в образ, нужно указать его в переменной RRECOMMENDS для соответствующей машины. Перечисленные ниже переменные полезны для установки конкретных модулей.

MACHINE_ESSENTIAL_EXTRA_RDEPENDS

MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS

MACHINE_EXTRA_RDEPENDS

MACHINE_EXTRA_RRECOMMENDS

Например, приведенная ниже строка из файла qemux86.conf включит модули ab123 в образ для машины qemux86.

     MACHINE_EXTRA_RRECOMMENDS += "kernel-module-ab123"

Дополнительная информация приведена в параграфе 2.10.2. Встраивание внешних модулей.

C.1.3. Изменение команды загрузки ядра

Командная строка ядра Linux обычно задается в конфигурации машины с помощью переменной APPEND. Например, для добавления отладочной информации можно задать

     APPEND += "printk.time=y initcall_debug debug"

Литература

[1] Yocto Project Reference Manual, https://www.yoctoproject.org/docs/2.7.1/ref-manual/ref-manual.html.

[2] Menuconfig,
https://en.wikipedia.org/wiki/Menuconfig.

[3] Source
Repositories, http://git.yoctoproject.org/.

[4] Yocto
Project Development Tasks Manual,
https://www.yoctoproject.org/docs/2.7.1/dev-manual/dev-manual.html.

[5] Yocto Project Board Support Package (BSP) Developer’s Guide, https://www.yoctoproject.org/docs/2.7.1/bsp-guide/bsp-guide.html.

[6] Yocto Project Quick Build, https://www.yoctoproject.org/docs/2.7.1/brief-yoctoprojectqs/brief-yoctoprojectqs.html.

[7] Yocto Project Overview and Concepts Manual, https://www.yoctoproject.org/docs/2.7.1/overview-manual/overview-manual.html.

[8] Yocto Project Application Development and the Extensible Software Development Kit (eSDK),
https://www.yoctoproject.org/docs/2.7.1/sdk-manual/sdk-manual.html
.

[9] BitBake User Manual, https://www.yoctoproject.org/docs/2.7.1/bitbake-user-manual/bitbake-user-manual.html.

Николай Малых

nmalykh@protokols.ru

1Long Term Support Initiative — инициатива долгосрочной поддержки.

2Software Development Kit — набор (комплект) для разработки программ.

3Board Support Package — пакет поддержки плат.

4Board Support Package — пакет поддержки плат.

5В некоторых дистрибутивах Linux имена пакетов могут отличаться. Например, в Mageia первый называется libncurses-devel (lib64ncurses-devel) и включает в себя второй.

6Source Control Manager — менеджер контроля исходных кодов.

7Long Term Support Initiative.

8Long Term Support — долгосрочная поддержка.

9Upward revision — пересмотр вверх.

10Source Code Manager — менеджер исходных кодов.

11Linux Kernel Configuration — конфигурация ядра Linux.

Рубрика: Linux | Комментарии к записи Руководство для разработчиков Yocto Project Linux Kernel отключены

trace-cmd — программа для работы с ftrace

trace-cmd

PDF

Программа для взаимодействия со встроенным трассировщиком ядра Linux ftrace.

Синтаксис

trace-cmd COMMAND [OPTIONS]

Описание

Программа trace-cmd взаимодействует с трассировщиком ftrace, встроенным в ядро Linux. Взаимодействие происходит через файлы файловой системы debugfs. Параметр COMMAND задает операции, выполняемые trace-cmd.

Разработчиком программы является Steven Rostedt, <rostedt@goodmis.org>, исходный код доступен по ссылке https://git.kernel.org/pub/scm/utils/trace-cmd/trace-cmd.git/.

Команды

record

Задает запись трассировки в файл trace.dat на локальном диске или через сеть.

report

Читает файл trace.dat и преобразует двоичные данные в удобочитаемый текст ASCII.

profile

Запускает профилирование и считывание вывода напрямую.

hist

Выводит гистограмму событий.

stat

Показывает статус системы трассировки (ftrace).

extract

Извлекает данные из кольцевого буфера ядра и создает файл trace.dat.

show

Показывает содержимое буфера трассировки ядра.

options

Выводит список опций плагинов, доступных для отчета.

start

Запускает трассировку без записи в файл trace.dat.

stop

Останавливает трассировку (прекращается лишь запись, а издержки трассировщика сохраняются).

restart

Повторно запускает остановленную ранее трассировку (воздействует лишь на запись).

reset

Отключает все трассировки, возвращая полную производительность системы (данные из буферов ядра теряются).

split

Расщепляет файл trace.dat на более мелкие файлы.

list

Выводит список доступных плагинов, событий и опций ftrace.

listen

Открывает порт для прослушивания соединений от удаленных точек трассировки.

restore

Восстанавливает файлы данных отказавшего запуска команды trace-cmd record.

stack

Запускает и показывает трассировщик стека.

check-events

Анализирует строки формата для всех событий и возвращает информацию о возможности разбора всех.

clear

Очищает буферы трассировки.

stream

Запускает трассировку и считывает вывод напрямую.

snapshot

Делает «моментальный снимок» действующей трассировки.

Опции

-h, —help

Выводит краткую справку о поддерживаемых командах.

Другие опции приведены в описаниях соответствующих команд.

record

Записывает трассировку из внутреннего трассировщика ядра Linux ftrace.

Синтаксис

trace-cmd record [OPTIONS] [command]

Описание

Команда trace-cmd record будет переводить встроенный трассировщик ядра Linux в режим записи указанных подключаемых модулей (plugin) и событий при выполнении пользовательской команды (command). Если команда для выполнения не указана, запись будет продолжаться до прерывания пользователем с помощью клавиш Ctrl-C.

При записи ftrace отслеживать события и подключаемые модули, указанные в командной строке. Это может приводить к запуску множества процессов трассировки (по одному на CPU), которые будут записываться из кольцевого буфера ядра напрямую во временные файлы. По завершении работы команды (или при нажатии Ctrl-C) все временные файлы будут объединены в один файл trace.dat, который потом может использоваться для анализа (см. report).

Опции

-p tracer

Задает трассировщик, который обычно не просто отслеживает события, но и выполняют другие операции. Обычно применяются трассировщики function, function_graph, preemptirqsoff, irqsoff, preemptoff и wakeup. Трассировщик должен поддерживаться работающим ядром. Список доступных трассировщиков можно посмотреть с помощью команды list.

-e event

Задает событие для трассировки. В ядре Linux имеется множество статических точек трассировки, сгруппированных по подсистемам, в которых можно включить все события или выбрать из них нужные. События указываются в формате subsystem:event-name. Можно просто указать подсистему без :event-name или event-name без subsystem:. Например, опция -e sched_switch будет включать событие sched_switch, а -e sched — все события подсистемы sched.

Параметр event может также включать шаблонные выражения. Т. е. *stat* будет выбирать все события (или подсистемы), в именах которых присутствует stat.

Для включения всех событий служит ключевое слово all.

-a

Каждое записываемое событие имеет файл формата, помещаемый в начало выходного файла трассировки (заголовок). Если разрешена трассировка событий, не известных trace-cmd, формат этих событий не будет записываться и отчет trace-cmd не будет включать их. В таких случаях опция -a позволяет сохранить формат для всех событий в системе.

-T

Включает трассировку стека для каждого события. Например,

	<idle>-0	[003] 58549.289091: sched_switch:	kworker/0:1:0 [120] R ==> trace-cmd:2603 [120] 
	<idle>-0	[003] 58549.289092: kernel_stack:	<stack trace> 
=> schedule (ffffffff814b260e) 
=> cpu_idle (ffffffff8100a38c) 
=> start_secondary (ffffffff814ab828)

—func-stack

Включает трассировку стека для всех функций. Отметим, что это применимо только для подключаемого модуля function и будет работать только с опцией -l для ограничения числа функций. Если трассировка функций не фильтруется и включена трассировка стека, это может «подвесить» машину.

-f filter

Задает фильтр для предыдущего события и должна следовать после опции -e. Опция обеспечивает фильтрацию записываемых событий на основе их содержимого. Фильтры передаются напрямую ядру, поэтому возможности фильтрации зависят от используемой версии ядра. По сути это позволяет применять нотацию языка C для решения вопроса об обработке события.

==, >=, <=, >, <, &, |, && and ||

Приведенные выше операторы обычно можно безопасно применять для сравнения полей.

—no-filter

Отключает фильтрацию потоков (thread) в trace-cmd. По умолчанию потоки фильтруются, чтобы не отслеживаться событиями. Эта опция приводит к отслеживанию потоков командой trace-cmd.

-R trigger

Задает триггер для предыдущего события и должна указываться после опции -e. Это позволяет добавить указанный триггер к данному событию. Чтобы включить лишь триггер, но не событие, следует поместить событие после опции -v.

Дополнительную информацию о триггерах можно найти в файле Documentation/trace/events.txt кода ядра Linux.

-v

Опция будет отключать трассировку всех событий, указанных после нее в командной строке. Это полезно при выборе подсистемы для трассировки с пропуском ненужных событий. Например, -e sched -v -e «*stat\*»» будет обеспечивать трассировку всех событий sched, за исключением тех, в имени которых присутствует stat.

Примечание. Опция -v была заимствована из grep, где она инвертирует последующие совпадения.

-F

Эта опция будет фильтровать лишь исполняемый файл, указанный в командной строке, а при отсутствии его — самое себя (бессмысленно). Использование опции -F позволяет трассировать лишь события, вызванные данной командой.

-P

Похожа на -F, но позволяет задать идентификатор процесса для трассировки.

-c

Используется с опцией -F (или -P, если ядро поддерживает ее) для трассировки также потомков процесса.

-C clock

Устанавливает значение clock для часов трассировки. Для проверки доступности часов используйте команду trace-cmd list -C.

-o output-file

По умолчанию отчет trace-cmd сохраняется в файле trace.dat, но эта опция позволяет задать другой файл.

-l function-name

Будет ограничивать трассировщики function и function_graph лишь указанной параметром function-name функцией. Для трассировки нескольких функций опция -l может указываться неоднократно. Возможно ограниченное применение выражений-шаблонов вида match*, когда будут трассироваться лишь функции, начинающиеся с match, и *match для функций, завершающихся match. Выражению *match\* будут соответствовать функции, содержащие match.

-g function-name

Эта опция служит для плагина function_graph и будет создавать граф заданной функции. Т. е. будет трассироваться только указанная функция и все вызываемые из нее функции. Опция -g может применяться многократно.

-n function-name

Опция имеет противоположный опции -l эффект — указанная -n функция не будет трассироваться. Эта опция имеет более высокий приоритет, поэтому при указании одной функции в -n и -l эта функция не будет трассироваться.

-d

Некоторые плагины трассировки (например, трассировщик задержек) включают трассировщик function по умолчанию. Эта опция предотвращает включение трассировки функций при старте.

-D

Опция -d будет пытаться использовать опцию function-trace для запрета трассировщика функции (если это возможно), в противном случае будет по умолчанию использоваться файл /proc/sys/kernel/ftrace_enabled, но без использования для него операции touch, если опция function-trace доступна. Опция -D будет отключать (0) файл /proc/ftrace_enabled, а также опцию function-trace, если она есть.

Отметим, что это отключение относится ко всем пользователям, включая находящихся вне трассировщиков ftrace (stack_tracer, perf и т. п.).

-O option

Трассировщик ftrace имеет различные опции, которые можно включать и отключать. Добавление no перед именем опции отключает ее. Например, -O nograph-time отключит опцию graph-time.

-s interval

Процессы, создаваемые trace-cmd для записи из кольцевого буфера, нужно активизировать. Установка нулевого интервала будут активизировать процессы при каждой новой записи данных в буфер. Однако, поскольку ftrace записывает активность ядра, возврат этих процессов в спящий режим может вызывать новые события, которые снова будут будить процесс, что приведет к добавлению в буфер избыточных данных.

Интервал задается в микросекундах и по умолчанию имеет значение 1000 (1 мсек). Это время, в течение которого каждый процесс будет находиться в спящем режиме, прежде чем проснуться для записи новых данных из кольцевого буфера.

-r priority

Приоритет для запуска захвата потоков. В загруженной системе потоки захвата трассировки могут быть заторможены с потерей событий. Данная опция повышает уровень приоритета до real time (FIFO). Опцию следует применять с осторожностью, поскольку она может менять поведение отслеживаемой системы.

-b size

Эта опция устанавливает размер кольцевого буфера в килобайтах. Поскольку кольцевые буферы ftrace работают на уровне CPU, заданный опцией размер выделяется в ядре для буфера каждого процессора. Опция -b 10000 на машине с 4 CPU будет создавать буферы ftrace общим размером 40 Мегабайт.

-B buffer-name

Если ядро поддерживает множество буферов, эта опция будет добавлять буфер с заданным именем. Если такой буфер уже имеется, он просто будут сброшен, а по завершении записи не будет удаляться. Если создается новый буфер, он будет удален по завершении записи (если не используется опция -k или команда start).

После создания буфера все последующие добавляемые события будут связываться с ним. Если буфер не задан или событие указано до создания буфера, оно будет связано с основным (верхнего уровня) буфером.

-m size

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

Применение этой опции позволяет предотвратить нехватку дискового пространства для журнальных файлов.

-M cpumask

Устанавливает маску процессора cpumask для трассировки. Опция влияет лишь на последний данный экземпляр буфера. Значение маски должно быть шестнадцатеричным числом.

trace-cmd record -p function -M c -B events13 -e all -M 5

Если опция -M пропущена, маска не изменяется. Для трассировки всех CPU используется маска -1.

-k

По умолчанию при завершении трассировки trace-cmd сбрасывает буферы и отключает все включенные трассировки. Эта опция отменяет выключение трассировки и сброс буферов. Опция полезна для отладки trace-cmd.

Примечание. Обычно trace-cmd возвращает файл tracing_on в состояние, существовавшее до вызова. Эта опция оставит нулевой (пустой) файл.

-i

По умолчанию trace-cmd завершает работу с ошибкой, если указанного в командной строке события не существует. Эта опция позволяет игнорировать события, указанные в командной строке, но не найденные в системе.

-N host:port

Если другая машина работает в режиме trace-cmd listen, эта опция позволяет передать данные такой машине по протоколу UDP. Вместо записи в выходной файл данные передаются удаленной машине. Это очень удобно для встраиваемых систем с небольшим хранилищем или для сохранения на одной машине данных с разных систем.

Примечание. Эта опция не поддерживается с плагинами трассировщиков задержки wakeup, wakeup_rt, irqsoff, preemptoff и preemptirqsoff

-t

Эта опция применяется вместе с -N, когда нужно передавать данные на удаленную машину по протоколу TCP вместо UDP. Хотя TCP работает медленней UDP, этот протокол может потребоваться в ненадежной сети, если объем передаваемых данных невелик, но нужна гарантированная доставка.

-q | —quiet

Подавляет обычный вывод программы (за исключением ошибок), отображая лишь данные отслеживаемого приложения.

—date

Опция задает trace-cmd запись временных меток в буфер трассировки по завершении записи. Опция будет отображать timestamp в gettimeofday для вывода системного времени при чтении созданного файла trace.dat.

—max-graph-depth depth

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

—module module

Задает фильтрацию имени модуля в трассировке. Это эквивалентно добавлению :mod:module после всех других функций, которые будут фильтроваться. Если других фильтров функцией не указано, будут фильтроваться все функции.

—module snd эквивалентно -l :mod:snd;

—module snd -l «*jack*»‘ эквивалентно -l «*jack*:mod:snd»;

—module snd -n «*»‘ эквивалентно -n :mod:snd.

—profile

С опцией —profile программа trace-cmd будет включать трассировку, которая может использоваться с командой trace-cmd report —profile. Если опция -p не задана и глубина графа функции поддерживается ядром, трассировщик function_graph будет включен с глубиной 1 (показывать лишь пользовательский вход в ядро). Будут также включены различные трассировочные точки с трассировкой стека, так что отчет может показать, где задачи были заблокированы дольше всего.

Дополнительная информация и примеры представлены в описании profile.

-H event-hooks

Добавляет пользовательское сопоставление событий для связывания вместе пары событий. При использовании вместе с опцией —profile параметр сохраняется и будет применяться также командой trace-cmd report —profile. Т. е. команды

trace-cmd record -H hrtimer_expire_entry,hrtimer/hrtimer_expire_exit,hrtimer,sp
trace-cmd report --profile

будут профилировать время hrtimer_expire_entry и hrtimer_expire_ext.

Формат приведен в описании profile.

-S

(только —profile) Включает лишь трассировщик или события, указанные в командной строке. С этой опцией трассировщик function_graph, равно как и другие события (такие как sched_switch) не включаются, пока не указаны явно в командной строке (например, -p function -e sched_switch -e sched_wakeup).

—ts-offset offset

Добавляет смещение для временных меток в файле trace.dat. Смещение задается в необработанных единицах, т. е. при записи меток в наносекундах смещение также будет в наносекундах, даже если для отображения применяются миллисекунды.

—stderr

Задает вывод в stderr вместо stdout без изменения выходного потока отслеживаемой команды. Это полезно в тех случаях, когда хочется видеть вывод команды без вывода trace-cmd.

Примеры

Базовый вариант трассировки всех событий

# trace-cmd record -e all ls > /dev/null 
# trace-cmd report 
	trace-cmd-13541 [003] 106260.693809: filemap_fault: address=0x128122 offset=0xce 
	trace-cmd-13543 [001] 106260.693809: kmalloc: call_site=81128dd4 ptr=0xffff88003dd83800 bytes_req=768 bytes_alloc=1024 gfp_flags=GFP_KERNEL|GFP_ZERO 
		ls-13545 [002] 106260.693809: kfree: call_site=810a7abb ptr=0x0 
		ls-13545 [002] 106260.693818: sys_exit_write: 	0x1

Для трассировки с отслеживанием sched_switch

# trace-cmd record -p function -e sched_switch ls > /dev/null 
# trace-cmd report 
		-13587 [002] 106467.860310: function: hrtick_start_fair <-- pick_next_task_fair 
		ls-13587 [002] 106467.860313: sched_switch: prev_comm=trace-cmd prev_pid=13587 prev_prio=120 prev_state=R ==> next_comm=trace-cmd next_pid=13583 next_prio=120 
	trace-cmd-13585 [001] 106467.860314: function: native_set_pte_at <-- __do_fault 
	trace-cmd-13586 [003] 106467.860314: function:	up_read <-- do_page_fault 
		ls-13587 [002] 106467.860317: function:	__phys_addr <-- schedule 
	trace-cmd-13585 [001] 106467.860318: function: _raw_spin_unlock <-- __do_fault 
		ls-13587 [002] 106467.860320: function: native_load_sp0 <-- __switch_to 
	trace-cmd-13586 [003] 106467.860322: function: down_read_trylock <-- do_page_fault

Ниже показан хороший способ обнаружить прерывания с наибольшей задержкой.

# trace-cmd record -p function_graph -e irq_handler_entry -l do_IRQ sleep 10 
# trace-cmd report 
	<idle>-0	[000] 157412.933969: funcgraph_entry:	|	do_IRQ() { 
	<idle>-0     [000] 157412.933974: irq_handler_entry:    irq=48 name=eth0 
	<idle>-0     [000] 157412.934004: funcgraph_exit:       + 36.358 us |  } 
	<idle>-0     [000] 157413.895004: funcgraph_entry:                  |  do_IRQ() { 
	<idle>-0     [000] 157413.895011: irq_handler_entry:    irq=48 name=eth0 
	<idle>-0     [000] 157413.895026: funcgraph_exit:                        + 24.014 us |  } 
	<idle>-0     [000] 157415.891762: funcgraph_entry:                  |  do_IRQ() { 
	<idle>-0     [000] 157415.891769: irq_handler_entry:    irq=48 name=eth0 
	<idle>-0     [000] 157415.891784: funcgraph_exit:       + 22.928 us |  } 
	<idle>-0     [000] 157415.934869: funcgraph_entry:                  |  do_IRQ() { 
	<idle>-0     [000] 157415.934874: irq_handler_entry:    irq=48 name=eth0 
	<idle>-0     [000] 157415.934906: funcgraph_exit:       + 37.512 us |  } 
	<idle>-0     [000] 157417.888373: funcgraph_entry:                  |  do_IRQ() { 
	<idle>-0     [000] 157417.888381: irq_handler_entry:    irq=48 name=eth0 
	<idle>-0     [000] 157417.888398: funcgraph_exit:       + 25.943 us |  }

Ниже приведен пример записи профиля.

# trace-cmd record --profile sleep 1 
# trace-cmd report --profile --comm sleep 
          task: sleep-21611 
            Event: sched_switch:R (1) Total: 99442 Avg: 99442 Max: 99442 Min:99442 
               <stack> 1 total:99442 min:99442 max:99442 avg=99442 
                 => ftrace_raw_event_sched_switch (0xffffffff8105f812) 
                 => __schedule (0xffffffff8150810a) 
                 => preempt_schedule (0xffffffff8150842e) 
                 => ___preempt_schedule (0xffffffff81273354) 
                 => cpu_stop_queue_work (0xffffffff810b03c5) 
                 => stop_one_cpu (0xffffffff810b063b) 
                 => sched_exec (0xffffffff8106136d) 
                 => do_execve_common.isra.27 (0xffffffff81148c89) 
                 => do_execve (0xffffffff811490b0)
                 => SyS_execve (0xffffffff811492c4) 
                 => return_to_handler (0xffffffff8150e3c8) 
                 => stub_execve (0xffffffff8150c699) 
            Event: sched_switch:S (1) Total: 1000506680 Avg: 1000506680 Max: 1000506680 Min:1000506680 
               <stack> 1 total:1000506680 min:1000506680 max:1000506680 avg=1000506680 
                 => ftrace_raw_event_sched_switch (0xffffffff8105f812) 
                 => __schedule (0xffffffff8150810a) 
                 => schedule (0xffffffff815084b8) 
                 => do_nanosleep (0xffffffff8150b22c) 
                 => hrtimer_nanosleep (0xffffffff8108d647) 
                 => SyS_nanosleep (0xffffffff8108d72c) 
                 => return_to_handler (0xffffffff8150e3c8) 
                 => tracesys_phase2 (0xffffffff8150c304) 
            Event: sched_wakeup:21611 (1) Total: 30326 Avg: 30326 Max: 30326 Min:30326 
               <stack> 1 total:30326 min:30326 max:30326 avg=30326 
                 => ftrace_raw_event_sched_wakeup_template (0xffffffff8105f653) 
                 => ttwu_do_wakeup (0xffffffff810606eb) 
                 => ttwu_do_activate.constprop.124 (0xffffffff810607c8) 
                 => try_to_wake_up (0xffffffff8106340a)

report

Показывает текст ASCII с результатами трассировки, записанной ранее в файл.

Синтаксис

trace-cmd report [OPTIONS] [input-file]

Описание

Команда trace-cmd report выводит понятный человеку отчет о трассировке, выполненной по команде trace-cmd record.

Опции

-i input-file

По умолчанию trace-cmd будет читать файл отчета trace.dat, но эта опция позволяет указать иной файл параметром input-file. Отметим, что входной файл можно также задать в конце командной строки (без опции -i).

-e

Эта опция позволяет увидеть тип файла отчета. Команда trace-cmd достаточно эффективна и может читать файлы big endian на машинах little endian и наоборот.

-f

Обеспечивает вывод списка функций, записанных в файл.

-P

Обеспечивает вывод списка данных trace_printk(). Необработанные данные трассировки показывают статические указатели в ядре. Эти данные должны сохраняться в файле трассировки.

-E

Обеспечивает вывод списка возможных событий в файле (это не обязательно список реально записанных событий).

—events

Обеспечивает вывод списка форматов событий, сохраненных в файле трассировки.

—event regex

Обеспечивает вывод событий, соответствующих регулярному выражению regex. При включении двоеточия символы перед ним служат для сопоставления системы, а символы после двоеточия — для сопоставления событий.

trace-cmd report --event sys:read

Приведенная выше команда будет соответствовать лишь системам, содержащим в имени sys, и событиям, содержащим read.

trace-cmd report --event read

Эта команда будет соответствовать всем событиям и системам, содержащим read в имени.

—check-events

Задает анализ строк формата событий в файле трассировки и возврат информации о возможности их корректного анализа. Опция ведет к загрузке плагинов, если не задана опция -N.

-t

Задает вывод временных меток, которые обычно записываются в файл данных в наносекундах, однако по умолчанию выводятся лишь миллисекунды. Эта опция позволяет увидеть временные метки полностью.

-F

Добавляет фильтр отображаемых событий. Формат фильтра показан ниже.

<events> ':' <filter>
<events> = SYSTEM'/'EVENT  | SYSTEM | EVENT | <events> ',' <events>
<filter> = EVENT_FIELD <op> <value> | <filter> '&&' <filter> | <filter> '||' <filter> | '(' <filter> ')' | '!' <filter>
<op> = '==' | '!=' | '>=' | '<=' | '>' | '<' | '&' | '|' | '^' | '+' | '-' | '*' | '/' | '%'
<value> = NUM | STRING | EVENT_FIELD

SYSTEM указывает имя системы для фильтра. Если поле EVENT опущено, фильтр применяется ко всем событиям SYSTEM. Если используется лишь одна строка без символа / для разделения SYSTEM и EVENT, фильтр будет применяться ко всем системам и событиям, соответствующим заданной строке.

Пробельные символы игнорируются, поэтому строки «sched:next_pid==123» и «sched : next_pid == 123» эквивалентны.

Строка STRING указывается в одинарных или двойных кавычках (одинаковых с обеих сторон), пробельные символы внутри кавычек принимаются во внимание.

В качестве SYSTEM и/или EVENT могут также указываться регулярные выражения, соответствующие regcomp.

EVENT_FIELD указывает имя фильтруемого поля в событии. Если событие не включает EVENT_FIELD, эта часть выражения считается ложной (false).

-F 'sched : bogus == 1 || common_pid == 2'

Выражение bogus == 1 всегда будет иметь значение FALSE, поскольку ни в одном событии нет поля bogus, но common_pid == 2 все равно будет проверяться, поскольку все события имеют поле common_pid. Все события sched, трассируемые процессом с PID = 2, будут показаны.

Отметим, что EVENT_FIELD является именем поля, показываемым в формате события (как при выводе с опцией *—events*), а не в выводе. Если вывод показывает ID:foo, но поле, к которому относится foo, называется name в формате события, в качестве фильтра нужно применять name. То же самое относится к значениям. Если отображаемое значение конвертировано в строку символов, фильтр проверяет исходное, а не отображаемое значение. Например, для фильтрации всех задач, которые работали в контексте switch служит выражение

-F 'sched/sched_switch : prev_state==0'

Хотя вывод показывает R, фильтр prev_stat==»R» не будет работать.

Примечание. Можно также указать COMM в качестве EVENT_FIELD. При этом для сравнения будет использоваться имя задачи (или or comm) в записи. Например, для фильтрации всех задач trace-cmd можно применить выражение

-F '.*:COMM != "trace-cmd"'

-I

Отключает вывод событий с установленным флагом задержки HARDIRQ. Это будет фильтровать большинство событий из контекста прерывания. Отметим, что это не поможет отфильтровать функции трассировки функций в контексте прерывания, которые были вызваны до установки флага ядра «in interrupt».

-S

Отключает вывод событий с установленным флагом задержки SOFTIRQ. Это будет фильтровать большинство событий из контекста программного прерывания.

-v

Включает фильтры, указанные в последующих опциях -F, для совпадающих событий.

-v -F 'sched/sched_switch : prev_state == 0'

Приведенное выражение исключит все события sched_switch с prev_state = 0. Удаление -v приведет лишь к выводу этих событий.

-T

Проверка фильтров опции -F. После обработки строки фильтра для каждого события будет выводиться результирующий фильтр. Это полезно при использовании фильтра для нескольких событий, когда поле может присутствовать во всех событиях может применяться также для гарантии отсутствия некорректно введенных имен событий, которые будет просто игнорироваться. Опция -T не принимается во внимание при отсутствии опции -F.

-V

Задает вывод загружаемых плагинов.

-L

Отменяет загрузку плагинов системного уровня, загружая лишь локальные (т. е. расположенные в каталоге ~/.trace-cmd/plugins).

-N

Отменяет загрузку всех плагинов.

-n event-re

Заставляет все события, соответствующие опции, игнорировать все зарегистрированные (плагинами) обработчики для вывода события, используя взамен обычный формат. Параметр event-re является регулярным выражением, соответствующим regcomp.

—profile

С этой опцией команда trace-cmd report будет сначала обрабатывать все события, а затем выводить формат, показывающий, где задачи тратили свое время в ядре, а также где они были дольше всего заблокированы и где была наибольшая задержка пробуждения.

Дополнительная информация и примеры приведены в описании команды profile.

-G

Устанавливает событие прерывания (программного или аппаратного) как глобальное (связанное с CPU, а не задачей). Работает только в опцией —profile.

-H event-hooks

Добавляет пользовательское сопоставление событий для связывания вместе пары событий.

Формат приведен в описании profile.

-R

Задает вывод событий в необработанном (raw) виде, т. е. форматирование для печати будет игнорироваться.

-r event-re

Задает вывод всех соответствующих опции событий в необработанном формате. Параметр event-re является регулярным выражением, соответствующим regcomp.

-l

Добавляет формат «вывода задержки». Информация о прерываниях и программные прерывания отключаются, устанавливается флаг need_resched, записывается счетчик вытеснения и большая блокировка ядра (big kernel lock) с каждым событием. Однако по умолчанию эта информация не отображается. Данная опция задает 6-символьное отображение отмеченных данных. Если одно из полей равно нулю или недоступно (N/A), выводится ‘.\’.

<idle>-0       0d.h1. 106467.859747: function:             ktime_get <-- tick_check_idle

Поле 0d.h1. указывает эту информацию. Точка никогда не бывает первым символом, который указывает на каком процессоре была записана трассировка (CPU 0). Буква d указывает запрет прерывания, h говорит о вызове внутри обработчика прерывания, 1 указывает, что для запрета вытеснения (preempt_count) было установлено значение 1. Две точки являются флагом need_resched и счетчиком блокировки ядра. Если флаг need_resched установлен, вместо точки будет показан символ N.

-w

Если включены события sched_switch и sched_wakeup, эта опция будет включать вывод задержки между первым вызовом задачи и запланированным временем.

-q

Отключает некритичные предупреждения.

-O

Передает опции в загружаемые плагины trace-cmd.

-O plugin:var=value

Параметры plugin: и =value являются необязательными. Значения логических параметров можно пропускать. Если параметр plugin: не включен, будут установлены любые переменные, соответствующие всем плагинам.

-O fgraph:tailprint --stat

Если в файле трассировки записана финальная статистика (выводится в конце записи), для ее извлечения может служить опция —stat.

—uname

Если в файл трассировки при выполнении записывались данные uname, опция будет извлекать эту информацию.

—version

Если в файл трассировки при выполнении записывалась версия исполняемой программы, опция обеспечивает ее вывод.

—ts-offset offset

Добавляет (вычитает при отрицательном значении) смещение ко всем временным меткам предыдущего файла данных, заданного опцией -i. Это полезно для сортируемого слияния множества файлов трассировки с разными временными метками, например, при выполнении трассировки на виртуальной машине одновременно с другой трассировкой на хосте. Если временная метка хоста опережает гостевую на 1000 единиц, можно воспользоваться командой

trace-cmd report -i host.dat --ts-offset -1000 -i guest.dat

Это будет вычитать 1000 единиц времени для всех событий на хосте при слиянии с событиями из файла guest.dat. Отметим, что единицы относятся к необработанным данным, записанным в файл. Если единицей является наносекунда, вычитаться или добавляться будут наносекунды даже при отображении времени в микросекундах.

—ts2secs HZ

Задает преобразование текущего источника времени во второй (с наносекундным разрешением) выход. При использовании часов типа x86-tsc и известной частоте время можно преобразовать в секунды путем указания частоты.

Эта опция влияет на любой файл трассировки, переданный с обработкой -i. Если опция расположена до всех опций -i, значение становится используемым по умолчанию преобразованием для всех других файлов трассировки. При наличии другой опции —ts2secs после -i trace.dat, эта опция будет переопределять принятое по умолчанию значение.

Например, при частоте 3.4 ГГц и командах

trace-cmd record -p function -C x86-tsc
trace-cmd report --ts2ns 3400000000

отчет будет преобразовывать временные метки тактов в читаемые значения секунд. По умолчанию будет применяться микросекундное разрешение, если не задана опция -t.

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

—ts-diff

Показывает временную разницу между событиями (в скобках после временной метки).

Примеры

При использовании файла trace.dat, созданного командой

# trace-cmd record -p function -e all sleep 5

отчет по умолчанию будет иметь вид

# trace-cmd report
	trace-cmd-16129 [002] 158126.498411: function: __mutex_unlock_slowpath <-- mutex_unlock 
	trace-cmd-16131 [000] 158126.498411: kmem_cache_alloc: call_site=811223c5 ptr=0xffff88003ecf2b40 bytes_req=272 bytes_alloc=320 gfp_flags=GFP_KERNEL|GFP_ZERO 
	trace-cmd-16130 [003] 158126.498411: function:             do_splice_to <-- sys_splice 
		sleep-16133 [001] 158126.498412: function: inotify_inode_queue_event <-- vfs_write 
	trace-cmd-16129 [002] 158126.498420: lock_release: 0xffff88003f1fa4f8 &sb->s_type->i_mutex_key 
	trace-cmd-16131 [000] 158126.498421: function: security_file_alloc <-- get_empty_filp 
		sleep-16133 [001] 158126.498422: function: __fsnotify_parent <-- vfs_write 
	trace-cmd-16130 [003] 158126.498422: function: rw_verify_area <-- do_splice_to 
	trace-cmd-16131 [000] 158126.498424: function: cap_file_alloc_security <-- security_file_alloc 
	trace-cmd-16129 [002] 158126.498425: function: syscall_trace_leave <-- int_check_syscall_exit_work 
		sleep-16133 [001] 158126.498426: function: inotify_dentry_parent_queue_event <-- vfs_write 
	trace-cmd-16130 [003] 158126.498426: function: security_file_permission <-- rw_verify_area 
	trace-cmd-16129 [002] 158126.498428: function: audit_syscall_exit <-- syscall_trace_leave 
	[…]

Для просмотра без трассировки функций служит команда

# trace-cmd report -v -F 'function' 
	trace-cmd-16131 [000] 158126.498411: kmem_cache_alloc: call_site=811223c5 ptr=0xffff88003ecf2b40 bytes_req=272 bytes_alloc=320 gfp_flags=GFP_KERNEL|GFP_ZERO 
	trace-cmd-16129 [002] 158126.498420: lock_release: 0xffff88003f1fa4f8 &sb->s_type->i_mutex_key 
	trace-cmd-16130 [003] 158126.498436: lock_acquire: 0xffffffff8166bf78 read all_cpu_access_lock 
	trace-cmd-16131 [000] 158126.498438: lock_acquire: 0xffff88003df5b520 read &fs->lock 
	trace-cmd-16129 [002] 158126.498446: kfree: call_site=810a7abb ptr=0x0 
	trace-cmd-16130 [003] 158126.498448: lock_acquire: 0xffff880002250a80 &per_cpu(cpu_access_lock, cpu) 
	trace-cmd-16129 [002] 158126.498450: sys_exit_splice:      0xfffffff5 
	trace-cmd-16131 [000] 158126.498454: lock_release: 0xffff88003df5b520 &fs->lock 
		sleep-16133 [001] 158126.498456: kfree: call_site=810a7abb ptr=0x0 
		sleep-16133 [001] 158126.498460: sys_exit_write:       0x1 
	trace-cmd-16130 [003] 158126.498462: kmalloc: call_site=810bf95b ptr=0xffff88003dedc040 bytes_req=24 bytes_alloc=32 gfp_flags=GFP_KERNEL|GFP_ZERO

Для просмотра лишь вызовов kmalloc с размером больше 1000 служит команда

#trace-cmd report -F 'kmalloc: bytes_req > 1000' 
	<idle>-0     [000] 158128.126641: kmalloc: call_site=81330635 ptr=0xffff88003c2fd000 bytes_req=2096 bytes_alloc=4096 gfp_flags=GFP_ATOMIC

Для просмотра пробуждений и sched_switch, оставивших предыдущую задачу в рабочем состоянии, служит команда

# trace-cmd report -F 'sched: prev_state == 0 || (success == 1)' 
trace-cmd-16132 [002] 158126.499951: sched_wakeup: comm=trace-cmd pid=16129 prio=120 success=1 target_cpu=002 
trace-cmd-16132 [002] 158126.500401: sched_switch: prev_comm=trace-cmd prev_pid=16132 prev_prio=120 prev_state=R ==> next_comm=trace-cmd next_pid=16129 next_prio=120 
	<idle>-0     [003] 158126.500585: sched_wakeup: comm=trace-cmd pid=16130 prio=120 success=1 target_cpu=003 
	<idle>-0     [003] 158126.501241: sched_switch: prev_comm=swapper prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=trace-cmd next_pid=16130 next_prio=120 
trace-cmd-16132 [000] 158126.502475: sched_wakeup: comm=trace-cmd pid=16131 prio=120 success=1 target_cpu=000
trace-cmd-16131 [002] 158126.506516: sched_wakeup: comm=trace-cmd pid=16129 prio=120 success=1 target_cpu=002 <idle>-0     [003] 158126.550110: sched_switch: prev_comm=swapper prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=trace-cmd next_pid=16130 next_prio=120 
trace-cmd-16131 [003] 158126.570243: sched_wakeup: comm=trace-cmd pid=16129 prio=120 success=1 target_cpu=003 trace-cmd-16130 [002] 158126.618202: sched_switch: prev_comm=trace-cmd prev_pid=16130 prev_prio=120 prev_state=R ==> next_comm=yum-updatesd next_pid=3088 next_prio=1 20 
trace-cmd-16129 [003] 158126.622379: sched_wakeup: comm=trace-cmd pid=16131 prio=120 success=1 target_cpu=003 trace-cmd-16129 [000] 158126.649287: sched_wakeup: comm=trace-cmd pid=16131 prio=120 success=1 target_cpu=000

Приведенный выше пример требует некоторых пояснений. Фильтр задает подсистему sched, включающую события sched_switch и sched_wakeup. Любое событие, не имеющее поля формата prev_state или success, будет давать для выражения значение FALSE (отсутствие совпадения). Использование || будет задавать проверку prev_state для sched_switch и success для sched_wakeup.

# trace-cmd report -w -F 'sched_switch, sched_wakeup.*' 
 [...] 
trace-cmd-16130 [003] 158131.580616: sched_wakeup: comm=trace-cmd pid=16131 prio=120 success=1 target_cpu=003 
trace-cmd-16129 [000] 158131.581502: sched_switch: prev_comm=trace-cmd prev_pid=16129 prev_prio=120 prev_state=S ==> next_comm=trace-cmd next_pid=16131 next_prio=120 Latency: 885.901 usecs 
trace-cmd-16131 [000] 158131.582414: sched_wakeup: comm=trace-cmd pid=16129 prio=120 success=1 target_cpu=000 
trace-cmd-16132 [001] 158131.583219: sched_switch: prev_comm=trace-cmd prev_pid=16132 prev_prio=120 prev_state=S ==> next_comm=trace-cmd next_pid=16129 next_prio=120 Latency: 804.809 usecs 
sleep-16133 [002] 158131.584121: sched_wakeup: comm=trace-cmd pid=16120 prio=120 success=1 target_cpu=002 
trace-cmd-16129 [001] 158131.584128: sched_wakeup: comm=trace-cmd pid=16132 prio=120 success=1 target_cpu=001 
sleep-16133 [002] 158131.584275: sched_switch: prev_comm=sleep prev_pid=16133 prev_prio=120 prev_state=R ==> next_comm=trace-cmd next_pid=16120 next_prio=120 Latency: 153.915 usecs 
trace-cmd-16130 [003] 158131.585284: sched_switch: prev_comm=trace-cmd prev_pid=16130 prev_prio=120 prev_state=S ==> next_comm=trace-cmd next_pid=16132 next_prio=120 Latency: 1155.677 usecs

Average wakeup latency: 26626.656 usecs

Приведенная выше трассировка показывает задержку пробуждения задач. Событие sched_switch указывает отдельную задержку после записи информации о событии. В конце отчета указана средняя задержка пробуждения.

# trace-cmd report -w -F 'sched_switch, sched_wakeup.*: prio < 100 || next_prio < 100' 
	<idle>-0     [003] 158131.516753: sched_wakeup: comm=ksoftirqd/3 pid=13 prio=49 success=1 target_cpu=003 
	<idle>-0     [003] 158131.516855: sched_switch: prev_comm=swapper prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/3 next_pid=13 next_prio=49 Latency: 101.244 usecs 
	<idle>-0     [003] 158131.533781: sched_wakeup: comm=ksoftirqd/3 pid=13 prio=49 success=1 target_cpu=003 
	<idle>-0     [003] 158131.533897: sched_switch: prev_comm=swapper prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/3 next_pid=13 next_prio=49 Latency: 115.608 usecs 
	<idle>-0     [003] 158131.569730: sched_wakeup: comm=ksoftirqd/3 pid=13 prio=49 success=1 target_cpu=003 
	<idle>-0     [003] 158131.569851: sched_switch: prev_comm=swapper prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/3 next_pid=13 next_prio=49 Latency: 121.024 usecs 

	Average wakeup latency: 110.021 usecs

Приведенный выше вариант показывает лишь пробуждения и переключатели контекста задач Real Time. Используемый в ядре приоритет prio имеет значение 0 в качестве максимального приоритета. Это значение 0 эквивалентно приоритету 99 в пользовательском пространстве, а пользовательский приоритет 98 эквивалентен приоритету 1 в ядре. Значения prio меньше 100 представляют задачи в реальном масштабе времени (Real Time).

Ниже приведен пример профиля.

# trace-cmd record --profile sleep 1 
           # trace-cmd report --profile --comm sleep 
          task: sleep-21611 
            Event: sched_switch:R (1) Total: 99442 Avg: 99442 Max: 99442 Min:99442 
               <stack> 1 total:99442 min:99442 max:99442 avg=99442 
                 => ftrace_raw_event_sched_switch (0xffffffff8105f812) 
                 => __schedule (0xffffffff8150810a) 
                 => preempt_schedule (0xffffffff8150842e) 
                 => ___preempt_schedule (0xffffffff81273354) 
                 => cpu_stop_queue_work (0xffffffff810b03c5) 
                 => stop_one_cpu (0xffffffff810b063b) 
                 => sched_exec (0xffffffff8106136d) 
                 => do_execve_common.isra.27 (0xffffffff81148c89) 
                 => do_execve (0xffffffff811490b0) 
                 => SyS_execve (0xffffffff811492c4) 
                 => return_to_handler (0xffffffff8150e3c8) 
                 => stub_execve (0xffffffff8150c699) 
            Event: sched_switch:S (1) Total: 1000506680 Avg: 1000506680 Max: 1000506680 Min:1000506680 
               <stack> 1 total:1000506680 min:1000506680 max:1000506680 avg=1000506680 
                 => ftrace_raw_event_sched_switch (0xffffffff8105f812) 
                 => __schedule (0xffffffff8150810a) 
                 => schedule (0xffffffff815084b8) 
                 => do_nanosleep (0xffffffff8150b22c) 
                 => hrtimer_nanosleep (0xffffffff8108d647) 
                 => SyS_nanosleep (0xffffffff8108d72c) 
                 => return_to_handler (0xffffffff8150e3c8) 
                 => tracesys_phase2 (0xffffffff8150c304) 
            Event: sched_wakeup:21611 (1) Total: 30326 Avg: 30326 Max: 30326 Min:30326 
               <stack> 1 total:30326 min:30326 max:30326 avg=30326 
                 => ftrace_raw_event_sched_wakeup_template (0xffffffff8105f653) 
                 => ttwu_do_wakeup (0xffffffff810606eb) 
                 => ttwu_do_activate.constprop.124 (0xffffffff810607c8) 
                 => try_to_wake_up (0xffffffff8106340a)

profile

Профилировка работы задачи.

Синтаксис

trace-cmd profile [OPTIONS] [command]

Описание

Команда trace-cmd profile будет запускать трассировку, подобно команде trace-cmd record —profile, за исключением того, что запись в файл не будет осуществляться и события будут считываться по мере возникновения с одновременным их учетом. По завершении трассировки будет выводиться отчет как по команде trace-cmd report —profile. Иными словами, команда profile работает подобно trace-cmd record —profile и trace-cmd report —profile без промежуточной записи данных на диск.

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

Эта команда включает некоторые события, а также трассировщик function_graph с глубиной 1 (если поддерживает ядро). Это позволяет видеть вход задач в ядро и выход из него, а также продолжительность обработки в ядре.

Для запрета вызова function_graph служит опция -p, включающая другой трассировщик. Для отключения всех трассировщиков служит -p nop.

Время при профилировании указывается в наносекундах.

Опции

Команда использует те же опции, что и trace-cmd record —profile.

-p tracer

Задает плагин трассировки для использования вместо function_graph с глубиной 1. Для отключения всех трассировщиков служит -p nop.

-S

Включает лишь трассировщик или события, указанные в командной строке. С этой опцией трассировщик function_graph, равно как и другие события (такие как sched_switch) не включаются, пока не указаны явно в командной строке (например, -p function -e sched_switch -e sched_wakeup).

-G

Устанавливает события прерываний (программных и аппаратных) как глобальные (связанные с CPU, а не задачей).

-o file

Задает запись профиля в файл file. Это заменяет опцию —stderr.

-H event-hooks

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

[<start_system>:]<start_event>,<start_match>[,<start_pid>]/ [<end_system>:]<end_event>,<end_match>[,<flags>]

Поле start_system:start_event (start_system не обязательно) указывает событие, с которого начинается отсчет времени. Поле start_match в стартовом событии служит для сопоставления с полем end_match в финальном событии. Параметр start_pid является необязательным, поскольку сопоставления присоединяются к задачам, которые запускают события. Если для поиска этой задачи следует применять другое поле, оно указывается start_pid. Параметр end_system:end_event указывает событие, на котором завершается отсчет времени (end_system не обязательно). Поле end_match в финальном событии сопоставляется с полем start_match в стартовом событии. Необязательное поле может включать приведенные ниже флаги (без учета регистра).

p — два события привязаны к одному CPU (начало и завершение всегда происходят на одном CPU).

s — событию следует иметь отслеживаемый стек (включается трассировка стека для стартового события).

g — событие является глобальным (не связано с задачей). Параметр start_pid не применим с этим флагом.

—stderr

Перенаправляет вывод профиля в stderr, не изменяя вывода трассируемой команды. Это позволяет видеть вывод команды, сохраняя вывод профиля в другом файле.

Примеры

# trace-cmd profile -F sleep 1 
[..] 
          task: sleep-1121 
            Event: sched_switch:R (2) Total: 234559 Avg: 117279 Max: 129886 Min:104673 
                    | 
                    + ftrace_raw_event_sched_switch (0xffffffff8109f310) 
                        100% (2) time:234559 max:129886 min:104673 avg:117279 
                         __schedule (0xffffffff816c1e81) 
                         preempt_schedule (0xffffffff816c236e) 
                         ___preempt_schedule (0xffffffff81351a59) 
                          | 
                          + unmap_single_vma (0xffffffff81198c05) 
                          |   55% (1) time:129886 max:129886 min:0 avg:129886 
                          |    stop_one_cpu (0xffffffff8110909a) 
                          |    sched_exec (0xffffffff810a119b) 
                          |    do_execveat_common.isra.31 (0xffffffff811de528) 
                          |    do_execve (0xffffffff811dea8c) 
                          |    SyS_execve (0xffffffff811ded1e) 
                          |    return_to_handler (0xffffffff816c8458) 
                          |    stub_execve (0xffffffff816c6929) 
                          | 
                          + unmap_single_vma (0xffffffff81198c05) 
                              45% (1) time:104673 max:104673 min:0 avg:104673 
                               unmap_vmas (0xffffffff81199174) 
                               exit_mmap (0xffffffff811a1f5b) 
                               mmput (0xffffffff8107699a) 
                               flush_old_exec (0xffffffff811ddb75)
                               load_elf_binary (0xffffffff812287df) 
                               search_binary_handler (0xffffffff811dd3e0) 
                               do_execveat_common.isra.31 (0xffffffff811de8bd) 
                               do_execve (0xffffffff811dea8c) 
                               SyS_execve (0xffffffff811ded1e) 
                               return_to_handler (0xffffffff816c8458) 
                               stub_execve (0xffffffff816c6929) 

          Event: sched_switch:S (1) Total: 1000513242 Avg: 1000513242 Max: 1000513242 Min:1000513242 
                  | 
                  + ftrace_raw_event_sched_switch (0xffffffff8109f310) 
                      100% (1) time:1000513242 max:1000513242 min:0 avg:1000513242 
                       __schedule (0xffffffff816c1e81) 
                       schedule (0xffffffff816c23b9) 
                       do_nanosleep (0xffffffff816c4f1c) 
                       hrtimer_nanosleep (0xffffffff810dcd86) 
                       SyS_nanosleep (0xffffffff810dcea6) 
                       return_to_handler (0xffffffff816c8458) 
                       tracesys_phase2 (0xffffffff816c65b0) 

          Event: sched_wakeup:1121 (1) Total: 43405 Avg: 43405 Max: 43405 Min:43405 
                  | 
                  + ftrace_raw_event_sched_wakeup_template (0xffffffff8109d960) 
                      100% (1) time:43405 max:43405 min:0 avg:43405 
                       ttwu_do_wakeup (0xffffffff810a01a2) 
                       ttwu_do_activate.constprop.122 (0xffffffff810a0236) 
                       try_to_wake_up (0xffffffff810a3ec3) 
                       wake_up_process (0xffffffff810a4057) 
                       hrtimer_wakeup (0xffffffff810db772) 
                       __run_hrtimer (0xffffffff810dbd91) 
                       hrtimer_interrupt (0xffffffff810dc6b7) 
                       local_apic_timer_interrupt (0xffffffff810363e7) 
                       smp_trace_apic_timer_interrupt (0xffffffff816c8c6a) 
                       trace_apic_timer_interrupt (0xffffffff816c725a) 
                       finish_task_switch (0xffffffff8109c3a4) 
                       __schedule (0xffffffff816c1e01) 
                       schedule (0xffffffff816c23b9) 
                       ring_buffer_wait (0xffffffff811323a3) 
                       wait_on_pipe (0xffffffff81133d93) 
                       tracing_buffers_splice_read (0xffffffff811350b0) 
                       do_splice_to (0xffffffff8120476f) 
                       SyS_splice (0xffffffff81206c1f) 
                       tracesys_phase2 (0xffffffff816c65b0) 

          Event: func: sys_nanosleep() (1) Total: 1000598016 Avg: 1000598016 Max: 1000598016 Min:1000598016 
          Event: func: sys_munmap() (1) Total: 14300 Avg: 14300 Max: 14300 Min:14300 
          Event: func: sys_arch_prctl() (1) Total: 571 Avg: 571 Max: 571 Min:571 
          Event: func: sys_mprotect() (4) Total: 14382 Avg: 3595 Max: 7196 Min:2190 
          Event: func: SyS_read() (1) Total: 2640 Avg: 2640 Max: 2640 Min:2640 
          Event: func: sys_close() (5) Total: 4001 Avg: 800 Max: 1252 Min:414
          Event: func: sys_newfstat() (3) Total: 11684 Avg: 3894 Max: 10206 Min:636 
          Event: func: SyS_open() (3) Total: 23615 Avg: 7871 Max: 10535 Min:4743 
          Event: func: sys_access() (1) Total: 5924 Avg: 5924 Max: 5924 Min:5924 
          Event: func: SyS_mmap() (8) Total: 39153 Avg: 4894 Max: 12354 Min:1518 
          Event: func: smp_trace_apic_timer_interrupt() (1) Total: 10298 Avg: 10298 Max: 10298 Min:10298 
          Event: func: SyS_brk() (4) Total: 2407 Avg: 601 Max: 1564 Min:206 
          Event: func: do_notify_resume() (2) Total: 4095 Avg: 2047 Max: 2521 Min:1574 
          Event: func: sys_execve() (5) Total: 1625251 Avg: 325050 Max: 1605698 Min:3570 
                  | 
                  + ftrace_raw_event_sched_wakeup_template (0xffffffff8109d960) 
                      100% (1) time:1605698 max:1605698 min:0 avg:1605698 
                       ttwu_do_wakeup (0xffffffff810a01a2) 
                       ttwu_do_activate.constprop.122 (0xffffffff810a0236) 
                       try_to_wake_up (0xffffffff810a3ec3) 
                       wake_up_process (0xffffffff810a4057) 
                       cpu_stop_queue_work (0xffffffff81108df8) 
                       stop_one_cpu (0xffffffff8110909a) 
                       sched_exec (0xffffffff810a119b) 
                       do_execveat_common.isra.31 (0xffffffff811de528) 
                       do_execve (0xffffffff811dea8c) 
                       SyS_execve (0xffffffff811ded1e) 
                       return_to_handler (0xffffffff816c8458) 
                       stub_execve (0xffffffff816c6929) 
                       stub_execve (0xffffffff816c6929) 

          Event: func: syscall_trace_enter_phase2() (38) Total: 21544 Avg: 566 Max: 1066 Min:329 
          Event: func: syscall_trace_enter_phase1() (38) Total: 9202 Avg: 242 Max: 376 Min:150 
          Event: func: __do_page_fault() (53) Total: 257672 Avg: 4861 Max: 27745 Min:458 
                  | 
                  + ftrace_raw_event_sched_wakeup_template (0xffffffff8109d960) 
                      100% (1) time:27745 max:27745 min:0 avg:27745 
                       ttwu_do_wakeup (0xffffffff810a01a2) 
                       ttwu_do_activate.constprop.122 (0xffffffff810a0236) 
                       try_to_wake_up (0xffffffff810a3ec3) 
                       default_wake_function (0xffffffff810a4002) 
                       autoremove_wake_function (0xffffffff810b50fd) 
                       __wake_up_common (0xffffffff810b4958) 
                       __wake_up (0xffffffff810b4cb8) 
                       rb_wake_up_waiters (0xffffffff8112f126) 
                       irq_work_run_list (0xffffffff81157d0f) 
                       irq_work_run (0xffffffff81157d5e) 
                       smp_trace_irq_work_interrupt (0xffffffff810082fc) 
                       trace_irq_work_interrupt (0xffffffff816c7aaa) 
                       return_to_handler (0xffffffff816c8458) 
                       trace_do_page_fault (0xffffffff810478b2) 
                       trace_page_fault (0xffffffff816c7dd2) 

          Event: func: syscall_trace_leave() (38) Total: 26145 Avg: 688 Max: 1264 Min:381 
          Event: func: __sb_end_write() (1) Total: 373 Avg: 373 Max: 373 Min:373 
          Event: func: fsnotify() (1) Total: 598 Avg: 598 Max: 598 Min:598
          Event: func: __fsnotify_parent() (1) Total: 286 Avg: 286 Max: 286 Min:286 
          Event: func: mutex_unlock() (2) Total: 39636 Avg: 19818 Max: 39413 Min:223 
          Event: func: smp_trace_irq_work_interrupt() (6) Total: 236459 Avg: 39409 Max: 100671 Min:634 
                  | 
                  + ftrace_raw_event_sched_wakeup_template (0xffffffff8109d960) 
                      100% (4) time:234348 max:100671 min:38745 avg:58587 
                       ttwu_do_wakeup (0xffffffff810a01a2) 
                       ttwu_do_activate.constprop.122 (0xffffffff810a0236) 
                       try_to_wake_up (0xffffffff810a3ec3) 
                       default_wake_function (0xffffffff810a4002) 
                       autoremove_wake_function (0xffffffff810b50fd) 
                       __wake_up_common (0xffffffff810b4958) 
                       __wake_up (0xffffffff810b4cb8) 
                       rb_wake_up_waiters (0xffffffff8112f126) 
                       irq_work_run_list (0xffffffff81157d0f) 
                       irq_work_run (0xffffffff81157d5e) 
                       smp_trace_irq_work_interrupt (0xffffffff810082fc) 
                       return_to_handler (0xffffffff816c8458) 
                       trace_irq_work_interrupt (0xffffffff816c7aaa) 
                        | 
                        + ftrace_return_to_handler (0xffffffff81140840) 
                        |   84% (3) time:197396 max:100671 min:38745 avg:65798 
                        |    return_to_handler (0xffffffff816c846d) 
                        |    trace_page_fault (0xffffffff816c7dd2) 
                        | 
                        + ftrace_return_to_handler (0xffffffff81140840) 
                            16% (1) time:36952 max:36952 min:0 avg:36952 
                             ftrace_graph_caller (0xffffffff816c8428) 
                             mutex_unlock (0xffffffff816c3f75) 
                             rb_simple_write (0xffffffff81133142) 
                             vfs_write (0xffffffff811d7727) 
                             SyS_write (0xffffffff811d7acf) 
                             tracesys_phase2 (0xffffffff816c65b0) 

          Event: sys_enter:35 (1) Total: 1000599765 Avg: 1000599765 Max: 1000599765 Min:1000599765 
          Event: sys_enter:11 (1) Total: 55025 Avg: 55025 Max: 55025 Min:55025 
          Event: sys_enter:158 (1) Total: 1584 Avg: 1584 Max: 1584 Min:1584 
          Event: sys_enter:10 (4) Total: 18359 Avg: 4589 Max: 8764 Min:2933 
          Event: sys_enter:0 (1) Total: 4223 Avg: 4223 Max: 4223 Min:4223 
          Event: sys_enter:3 (5) Total: 9948 Avg: 1989 Max: 2606 Min:1203 
          Event: sys_enter:5 (3) Total: 15530 Avg: 5176 Max: 11840 Min:1405 
          Event: sys_enter:2 (3) Total: 28002 Avg: 9334 Max: 12035 Min:5656 
          Event: sys_enter:21 (1) Total: 7814 Avg: 7814 Max: 7814 Min:7814 
          Event: sys_enter:9 (8) Total: 49583 Avg: 6197 Max: 14137 Min:2362 
          Event: sys_enter:12 (4) Total: 108493 Avg: 27123 Max: 104079 Min:922 
          Event: sys_enter:59 (5) Total: 1631608 Avg: 326321 Max: 1607529 Min:4563 
          Event: page_fault_user:0x398d86b630 (1) 
          Event: page_fault_user:0x398d844de0 (1) 
          Event: page_fault_user:0x398d8d9020 (1) 
          Event: page_fault_user:0x1d37008 (1)
          Event: page_fault_user:0x7f0b89e91074 (1) 
          Event: page_fault_user:0x7f0b89d98ed0 (1) 
          Event: page_fault_user:0x7f0b89ec8950 (1) 
          Event: page_fault_user:0x7f0b89d83644 (1) 
          Event: page_fault_user:0x7f0b89d622a8 (1) 
          Event: page_fault_user:0x7f0b89d5a560 (1) 
          Event: page_fault_user:0x7f0b89d34010 (1) 
          Event: page_fault_user:0x1d36008 (1) 
          Event: page_fault_user:0x398d900510 (1) 
          Event: page_fault_user:0x398dbb3ae8 (1) 
          Event: page_fault_user:0x398d87f490 (1) 
          Event: page_fault_user:0x398d8eb660 (1) 
          Event: page_fault_user:0x398d8bd730 (1) 
          Event: page_fault_user:0x398d9625d9 (1) 
          Event: page_fault_user:0x398d931810 (1) 
          Event: page_fault_user:0x398dbb7114 (1) 
          Event: page_fault_user:0x398d837610 (1) 
          Event: page_fault_user:0x398d89e860 (1) 
          Event: page_fault_user:0x398d8f23b0 (1) 
          Event: page_fault_user:0x398dbb4510 (1) 
          Event: page_fault_user:0x398dbad6f0 (1) 
          Event: page_fault_user:0x398dbb1018 (1) 
          Event: page_fault_user:0x398d977b37 (1) 
          Event: page_fault_user:0x398d92eb60 (1) 
          Event: page_fault_user:0x398d8abff0 (1) 
          Event: page_fault_user:0x398dbb0d30 (1) 
          Event: page_fault_user:0x398dbb6c24 (1) 
          Event: page_fault_user:0x398d821c50 (1) 
          Event: page_fault_user:0x398dbb6c20 (1) 
          Event: page_fault_user:0x398d886350 (1) 
          Event: page_fault_user:0x7f0b90125000 (1) 
          Event: page_fault_user:0x7f0b90124740 (1) 
          Event: page_fault_user:0x7f0b90126000 (1) 
          Event: page_fault_user:0x398d816230 (1) 
          Event: page_fault_user:0x398d8002b8 (1) 
          Event: page_fault_user:0x398dbb0b40 (1) 
          Event: page_fault_user:0x398dbb2880 (1) 
          Event: page_fault_user:0x7f0b90141cc6 (1) 
          Event: page_fault_user:0x7f0b9013b85c (1) 
          Event: page_fault_user:0x7f0b90127000 (1) 
          Event: page_fault_user:0x606e70 (1) 
          Event: page_fault_user:0x7f0b90144010 (1) 
          Event: page_fault_user:0x7fffcb31b038 (1) 
          Event: page_fault_user:0x606da8 (1) 
          Event: page_fault_user:0x400040 (1) 
          Event: page_fault_user:0x398d222218 (1) 
          Event: page_fault_user:0x398d015120 (1) 
          Event: page_fault_user:0x398d220ce8 (1) 
          Event: page_fault_user:0x398d220b80 (1) 
          Event: page_fault_user:0x7fffcb2fcff8 (1)
          Event: page_fault_user:0x398d001590 (1) 
          Event: page_fault_user:0x398d838490 (1) 
          Event: softirq_raise:RCU (3) Total: 252931 Avg: 84310 Max: 243288 Min:4639 
          Event: softirq_raise:SCHED (2) Total: 241249 Avg: 120624 Max: 239076 Min:2173 
                  | 
                  + ftrace_raw_event_sched_wakeup_template (0xffffffff8109d960) 
                      100% (1) time:239076 max:239076 min:0 avg:239076 
                       ttwu_do_wakeup (0xffffffff810a01a2) 
                       ttwu_do_activate.constprop.122 (0xffffffff810a0236) 
                       try_to_wake_up (0xffffffff810a3ec3) 
                       default_wake_function (0xffffffff810a4002) 
                       autoremove_wake_function (0xffffffff810b50fd) 
                       __wake_up_common (0xffffffff810b4958) 
                       __wake_up (0xffffffff810b4cb8) 
                       rb_wake_up_waiters (0xffffffff8112f126) 
                       irq_work_run_list (0xffffffff81157d0f) 
                       irq_work_run (0xffffffff81157d5e) 
                       smp_trace_irq_work_interrupt (0xffffffff810082fc) 
                       trace_irq_work_interrupt (0xffffffff816c7aaa) 
                       irq_exit (0xffffffff8107dd66) 
                       smp_trace_apic_timer_interrupt (0xffffffff816c8c7a) 
                       trace_apic_timer_interrupt (0xffffffff816c725a) 
                       prepare_ftrace_return (0xffffffff8103d4fd) 
                       ftrace_graph_caller (0xffffffff816c8428) 
                       mem_cgroup_begin_page_stat (0xffffffff811cfd25) 
                       page_remove_rmap (0xffffffff811a4fc5) 
                       stub_execve (0xffffffff816c6929) 
                       unmap_single_vma (0xffffffff81198b1c) 
                       unmap_vmas (0xffffffff81199174) 
                       exit_mmap (0xffffffff811a1f5b) 
                       mmput (0xffffffff8107699a) 
                       flush_old_exec (0xffffffff811ddb75) 
                       load_elf_binary (0xffffffff812287df) 
                       search_binary_handler (0xffffffff811dd3e0) 
                       do_execveat_common.isra.31 (0xffffffff811de8bd) 
                       do_execve (0xffffffff811dea8c) 
                       SyS_execve (0xffffffff811ded1e) 
                       return_to_handler (0xffffffff816c8458) 

          Event: softirq_raise:HI (3) Total: 72472 Avg: 24157 Max: 64186 Min:3430 
          Event: softirq_entry:RCU (2) Total: 3191 Avg: 1595 Max: 1788 Min:1403 
                  | 
                  + ftrace_raw_event_sched_wakeup_template (0xffffffff8109d960) 
                      100% (1) time:1788 max:1788 min:0 avg:1788 
                       ttwu_do_wakeup (0xffffffff810a01a2) 
                       ttwu_do_activate.constprop.122 (0xffffffff810a0236) 
                       try_to_wake_up (0xffffffff810a3ec3) 
                       default_wake_function (0xffffffff810a4002) 
                       autoremove_wake_function (0xffffffff810b50fd) 
                       __wake_up_common (0xffffffff810b4958)
                       __wake_up (0xffffffff810b4cb8) 
                       rb_wake_up_waiters (0xffffffff8112f126) 
                       irq_work_run_list (0xffffffff81157d0f) 
                       irq_work_run (0xffffffff81157d5e) 
                       smp_trace_irq_work_interrupt (0xffffffff810082fc) 
                       trace_irq_work_interrupt (0xffffffff816c7aaa) 
                       irq_work_queue (0xffffffff81157e95) 
                       ring_buffer_unlock_commit (0xffffffff8113039f) 
                       __buffer_unlock_commit (0xffffffff811367d5) 
                       trace_buffer_unlock_commit (0xffffffff811376a2) 
                       ftrace_event_buffer_commit (0xffffffff81146d5f) 
                       ftrace_raw_event_sched_process_exec (0xffffffff8109c511) 
                       do_execveat_common.isra.31 (0xffffffff811de9a3) 
                       do_execve (0xffffffff811dea8c) 
                       SyS_execve (0xffffffff811ded1e) 
                       return_to_handler (0xffffffff816c8458) 
                       stub_execve (0xffffffff816c6929) 

           Event: softirq_entry:SCHED (2) Total: 2289 Avg: 1144 Max: 1350 Min:939 
           Event: softirq_entry:HI (3) Total: 180146 Avg: 60048 Max: 178969 Min:499 
                   | 
                   + ftrace_raw_event_sched_wakeup_template (0xffffffff8109d960) 
                       100% (1) time:178969 max:178969 min:0 avg:178969 
                        ttwu_do_wakeup (0xffffffff810a01a2) 
                        ttwu_do_activate.constprop.122 (0xffffffff810a0236) 
                        try_to_wake_up (0xffffffff810a3ec3) 
                        wake_up_process (0xffffffff810a4057) 
                        wake_up_worker (0xffffffff8108de74) 
                        insert_work (0xffffffff8108fca6) 
                        __queue_work (0xffffffff8108fe12) 
                        delayed_work_timer_fn (0xffffffff81090088) 
                        call_timer_fn (0xffffffff810d8f89) 
                        run_timer_softirq (0xffffffff810da8a1) 
                        __do_softirq (0xffffffff8107d8fa) 
                        irq_exit (0xffffffff8107dd66) 
                        smp_trace_apic_timer_interrupt (0xffffffff816c8c7a) 
                        trace_apic_timer_interrupt (0xffffffff816c725a) 
                        prepare_ftrace_return (0xffffffff8103d4fd) 
                        ftrace_graph_caller (0xffffffff816c8428) 
                        mem_cgroup_begin_page_stat (0xffffffff811cfd25) 
                        page_remove_rmap (0xffffffff811a4fc5) 
                        stub_execve (0xffffffff816c6929) 
                        unmap_single_vma (0xffffffff81198b1c) 
                        unmap_vmas (0xffffffff81199174) 
                        exit_mmap (0xffffffff811a1f5b) 
                        mmput (0xffffffff8107699a) 
                        flush_old_exec (0xffffffff811ddb75) 
                        load_elf_binary (0xffffffff812287df) 
                        search_binary_handler (0xffffffff811dd3e0) 
                        do_execveat_common.isra.31 (0xffffffff811de8bd)
                        do_execve (0xffffffff811dea8c) 
                        SyS_execve (0xffffffff811ded1e) 
                        return_to_handler (0xffffffff816c8458)

В приведенном выше примере используется опция -F для отслеживания спящих задач, которая фильтрует события, относящиеся к сну. Отметим, что для отслеживания ветвлений нужно также указать опцию -c.

Другие задачи тоже будут включены в профиль, если события указывают более одной задачи (подобно sched_switch и sched_wakeup — prev_pid и next_pid для sched_switch, common_pid и pid для sched_wakeup).

Трассировки стека присоединяются к событиям, с которыми они связаны.

Рассмотрим приведенный ниже вывод.

Event: sched_switch:R (2) Total: 234559 Avg: 117279 Max: 129886 Min:104673

Это показывает, что задача была вытеснена (находится в состоянии R). Задача была вытеснена дважды в целом на 234559 нсек со средним временем вытеснения 117279 нсек, максимальным 128886 нсек и минимальным 104673 нсек.

Дерево ниже показывает точки вытеснения.

          | 
          + ftrace_raw_event_sched_switch (0xffffffff8109f310) 
              100% (2) time:234559 max:129886 min:104673 avg:117279 
               __schedule (0xffffffff816c1e81) 
               preempt_schedule (0xffffffff816c236e) 
               ___preempt_schedule (0xffffffff81351a59) 
                | 
                + unmap_single_vma (0xffffffff81198c05) 
                |   55% (1) time:129886 max:129886 min:0 avg:129886 
                |    stop_one_cpu (0xffffffff8110909a) 
                |    sched_exec (0xffffffff810a119b) 
                |    do_execveat_common.isra.31 (0xffffffff811de528) 
                |    do_execve (0xffffffff811dea8c) 
                |    SyS_execve (0xffffffff811ded1e) 
                |    return_to_handler (0xffffffff816c8458) 
                |    stub_execve (0xffffffff816c6929) 
                | 
                + unmap_single_vma (0xffffffff81198c05) 
                    45% (1) time:104673 max:104673 min:0 avg:104673 
                     unmap_vmas (0xffffffff81199174) 
                     exit_mmap (0xffffffff811a1f5b) 
                     mmput (0xffffffff8107699a) 
                     flush_old_exec (0xffffffff811ddb75) 
                     load_elf_binary (0xffffffff812287df) 
                     search_binary_handler (0xffffffff811dd3e0) 
                     do_execveat_common.isra.31 (0xffffffff811de8bd) 
                     do_execve (0xffffffff811dea8c) 
                     SyS_execve (0xffffffff811ded1e) 
                     return_to_handler (0xffffffff816c8458)
                     stub_execve (0xffffffff816c6929) 

          Event: sched_switch:S (1) Total: 1000513242 Avg: 1000513242 Max: 1000513242 Min:10005132

Это показывает, что задача была запланирована в состоянии INTERRUPTIBLE (прерываемая) один раз на суммарное время 1000513242 нсек (~1 сек.), что соответствует sleep 1.

После запланированных событий выводятся функциональные события. По умолчанию используется трассировщик function_graph, если установка глубины поддерживается ядром. Устанавливается глубина 1, при которой будет отслеживаться лишь первая функция входа в ядро. Будет записано также время выполнения в ядре.

Event: func: sys_nanosleep() (1) Total: 1000598016 Avg: 1000598016 Max: 1000598016 Min:1000598016 
Event: func: sys_munmap() (1) Total: 14300 Avg: 14300 Max: 14300 Min:14300 
Event: func: sys_arch_prctl() (1) Total: 571 Avg: 571 Max: 571 Min:571 
Event: func: sys_mprotect() (4) Total: 14382 Avg: 3595 Max: 7196 Min:2190 
Event: func: SyS_read() (1) Total: 2640 Avg: 2640 Max: 2640 Min:2640 
Event: func: sys_close() (5) Total: 4001 Avg: 800 Max: 1252 Min:414 
Event: func: sys_newfstat() (3) Total: 11684 Avg: 3894 Max: 10206 Min:636 
Event: func: SyS_open() (3) Total: 23615 Avg: 7871 Max: 10535 Min:4743 
Event: func: sys_access() (1) Total: 5924 Avg: 5924 Max: 5924 Min:5924 
Event: func: SyS_mmap() (8) Total: 39153 Avg: 4894 Max: 12354 Min:1518 
Event: func: smp_trace_apic_timer_interrupt() (1) Total: 10298 Avg: 10298 Max: 10298 Min:10298 
Event: func: SyS_brk() (4) Total: 2407 Avg: 601 Max: 1564 Min:206 
Event: func: do_notify_resume() (2) Total: 4095 Avg: 2047 Max: 2521 Min:1574 
Event: func: sys_execve() (5) Total: 1625251 Avg: 325050 Max: 1605698 Min:3570 

      Count of times the event was hit is always in parenthesis (5).

Трассировка function_graph может вызывать очень большие издержки, поскольку она продолжает срабатывать для всех (а не только отслеживаемых) функций. Для ограничения числа системных вызовов (не прерываний) можно использовать опции:

-l 'sys_*' -l 'SyS_*'

Для полного отключения function_graph служит опция

-p nop

Для трассировки функций (отметим, что будет записываться не время, а лишь число вызовов функции) служит опция

-p function

Показанные ниже функции являются записываемыми событиями.

          Event: sys_enter:35 (1) Total: 1000599765 Avg: 1000599765 Max: 1000599765 Min:1000599765 
          Event: sys_enter:11 (1) Total: 55025 Avg: 55025 Max: 55025 Min:55025 
          Event: sys_enter:158 (1) Total: 1584 Avg: 1584 Max: 1584 Min:1584 
          Event: sys_enter:10 (4) Total: 18359 Avg: 4589 Max: 8764 Min:2933 
          Event: sys_enter:0 (1) Total: 4223 Avg: 4223 Max: 4223 Min:4223 
          Event: sys_enter:3 (5) Total: 9948 Avg: 1989 Max: 2606 Min:1203 
          Event: sys_enter:5 (3) Total: 15530 Avg: 5176 Max: 11840 Min:1405 
          Event: sys_enter:2 (3) Total: 28002 Avg: 9334 Max: 12035 Min:5656 
          Event: sys_enter:21 (1) Total: 7814 Avg: 7814 Max: 7814 Min:7814
          Event: sys_enter:9 (8) Total: 49583 Avg: 6197 Max: 14137 Min:2362 
          Event: sys_enter:12 (4) Total: 108493 Avg: 27123 Max: 104079 Min:922 
          Event: sys_enter:59 (5) Total: 1631608 Avg: 326321 Max: 1607529 Min:4563

Это необработанные события системных вызовов с указанием идентификатора вызова после sys_enter:. Например, 59 — это execve. Почему эта функция вызывалась 5 раз? Рассмотрение strace показывает

          execve("/usr/lib64/ccache/sleep", ["sleep", "1"], [/* 27 vars */] <unfinished ...> 
          <... execve resumed> )      = -1 ENOENT (No such file or directory) 
          execve("/usr/local/sbin/sleep", ["sleep", "1"], [/* 27 vars */] <unfinished ...> 
          <... execve resumed> )      = -1 ENOENT (No such file or directory) 
          execve("/usr/local/bin/sleep", ["sleep", "1"], [/* 27 vars */] <unfinished ...> 
          <... execve resumed> )      = -1 ENOENT (No such file or directory) 
          execve("/usr/sbin/sleep", ["sleep", "1"], [/* 27 vars */] <unfinished ...> 
          <... execve resumed> )      = -1 ENOENT (No such file or directory) 
          execve("/usr/bin/sleep", ["sleep", "1"], [/* 27 vars */] <unfinished ...> 
          <... execve resumed> )      = 0

Видно попытку выполнить команду sleep для каждого пути в $PATH, пока не будет найден исполняемый файл.

События page_fault_user показывают, какой адрес в пользовательском пространстве принимает отказ страницы.

          Event: softirq_raise:RCU (3) Total: 252931 Avg: 84310 Max: 243288 Min:4639 
          Event: softirq_raise:SCHED (2) Total: 241249 Avg: 120624 Max: 239076 Min:2173 
                  | 
                  + ftrace_raw_event_sched_wakeup_template (0xffffffff8109d960) 
                      100% (1) time:239076 max:239076 min:0 avg:239076 
                       ttwu_do_wakeup (0xffffffff810a01a2) 
                       ttwu_do_activate.constprop.122 (0xffffffff810a0236) 
                       try_to_wake_up (0xffffffff810a3ec3) 
                       default_wake_function (0xffffffff810a4002) 
                       autoremove_wake_function (0xffffffff810b50fd) 
                       __wake_up_common (0xffffffff810b4958) 
                       __wake_up (0xffffffff810b4cb8) 
                       rb_wake_up_waiters (0xffffffff8112f126) 
                       irq_work_run_list (0xffffffff81157d0f) 
                       irq_work_run (0xffffffff81157d5e) 
                       smp_trace_irq_work_interrupt (0xffffffff810082fc) 
                       trace_irq_work_interrupt (0xffffffff816c7aaa) 
                       irq_exit (0xffffffff8107dd66)

Время событий softirq_raise измеряет интервал от поднятия softirq до момента завершения прерывания.

Время softirq_entry показывает продолжительность выполнения softirq.

Трассировка стека для softirq (и возможно других событий) используется в тех случаях, когда стек присоединен к событию. Это может происходить, если профиль запускает больше стеков, чем просто события sched, или события отбрасываются и стекируются.

Для полного контроля трассировки служит опция -S, по которой trace-cmd не будет включать трассировщики событий и function_graph, показывая лишь события, указанные в командной строке.

Если нужно видеть лишь время kmalloc и место записи, опция -S и включение трассировки стека и function_graph лишь для нужной функции будут давать профиль лишь для этой функции.

          # trace-cmd profile -S -p function_graph -l '*kmalloc*' -l '*kmalloc*:stacktrace' sleep 1 
          task: sshd-11786 
            Event: func: __kmalloc_reserve.isra.59() (2) Total: 149684 Avg: 74842 Max: 75598 Min:74086 
                    | 
                    + __alloc_skb (0xffffffff815a8917) 
                    |   67% (2) time:149684 max:75598 min:74086 avg:74842 
                    |    __kmalloc_node_track_caller (0xffffffff811c6635) 
                    |    __kmalloc_reserve.isra.59 (0xffffffff815a84ac) 
                    |    return_to_handler (0xffffffff816c8458) 
                    |    sk_stream_alloc_skb (0xffffffff81604ea1) 
                    |    tcp_sendmsg (0xffffffff8160592c) 
                    |    inet_sendmsg (0xffffffff8162fed1) 
                    |    sock_aio_write (0xffffffff8159f9fc) 
                    |    do_sync_write (0xffffffff811d694a) 
                    |    vfs_write (0xffffffff811d7825) 
                    |    SyS_write (0xffffffff811d7adf) 
                    |    system_call_fastpath (0xffffffff816c63d2) 
                    | 
                    + __alloc_skb (0xffffffff815a8917) 
                        33% (1) time:74086 max:74086 min:74086 avg:74086 
                         __alloc_skb (0xffffffff815a8917) 
                         sk_stream_alloc_skb (0xffffffff81604ea1) 
                         tcp_sendmsg (0xffffffff8160592c) 
                         inet_sendmsg (0xffffffff8162fed1) 
                         sock_aio_write (0xffffffff8159f9fc) 
                         do_sync_write (0xffffffff811d694a) 
                         vfs_write (0xffffffff811d7825) 
                         SyS_write (0xffffffff811d7adf) 
                         system_call_fastpath (0xffffffff816c63d2) 
           [..]

Для наблюдения вывода команды с сохранением вывода профиля в файл служит опция —stderr и перенаправление стандартного вывода ошибок в файл

# trace-cmd profile --stderr cyclictest -p 80 -n -t1 2> profile.out

или просто -o

# trace-cmd profile -o profile.out cyclictest -p 80 -n -t1

hist

Показывает гистограмму событий, записанных в файл трассировки.

Синтаксис

trace-cmd hist [OPTIONS][input-file]

Описание

Команда trace-cmd hist выводит гистограмму событий из файла трассировки. Вместо показа событий в упорядоченном виде создается гистограмма, которая может отображаться по задачам или для всех задач с выводом наиболее общих событий в начале. Команда использует трассировщик функций и стеки вызовов для построения гистограммы событий.

Опции

-i input-file

По умолчанию trace-cmd hist будет считывать данные из файла trace.dat, но с помощью этой опции можно задать другой файл (input-file). Отметим, что входной файл может быть также указан последним параметром командной строки.

-P

Задает компактирование всех событий и отображение вызовов с игнорированием задач и разных PID. Вместо указания имен задач все цепочки группируются и выводятся как <all pids>.

stat

Показывает статус системы трассировки (ftrace).

Синтаксис

trace-cmd stat

Описание

Команда trace-cmd stat выводит статус системы трассировки (ftrace).

Tracer — если один из трассировщиков (таких как function_graph) активен, в остальных случаях не выводится ничего.

Events — список событий, которые разрешены.

Event filters — показывает любые фильтры, установленные для любых событий.

Function filters — показывает любые фильтры, установленные для любых трассировщиков функций.

Graph functions — показывает любые функции, которые трассировщику function_graph следует отображать.

Buffers — показывает размер буфера трассировки. По умолчанию буферы трассировки в процессе использования находятся в сжатом формате и отображение буфера не представляется.

Trace clock — если трассировочные часы отличаются от принятых по умолчанию локальных часов (local), они будут указаны.

Trace CPU mask — если не все доступные CPU попадают в маску трассировки, указывается эта маска.

Trace max latency — указывает значение максимальной задержки трассировки, если оно отлично от 0.

Kprobes — показывает любые kprobe, определенные для трассировки.

Uprobes — показывает любые uprobe, определенные для трассировки.

extract

Извлекает данные трассировщика Linux ftrace.

Синтаксис

trace-cmd extract [OPTIONS]

Описание

Команда trace-cmd extract обычно применяется после trace-cmd-start и trace-cmd-stop, а также может применяться после запуска трассировщика ftrace вручную через псевдофайловую систему.

Команда extract создает файл trace.dat, который может использоваться trace-cmd report для считывания и анализа данных. Исходные данные для создания файла trace.dat извлекаются из внутреннего кольцевого буфера ядра.

Опции

-p plugin

Хотя команда extract не запускает никакой трассировки, некоторые плагины требуют чтения вывода в формате ASCII. К ним относятся трассировщики задержки, поскольку они используют отдельный внутренний буфер. Опция нужна лишь для плагинов wakeup, wakeup-rt, irqsoff, preemptoff и preemptirqsoff.

Без этой опции команда extract будет извлекать внутренние буферы ftrace.

-O option

Если извлекается трассировка задержки и применяется опция -p, некоторые опции ftrace могут менять формат. Данная опция будет менять их до извлечения. Просмотреть опции можно с помощью команды trace-cmd list. Для включения опции указывается ее имя, для отключения имя указывается с префиксом no. Например, noprint-parent будет отключать опцию print-parent, которая выводит родительскую функцию при отображении функционального события.

-o outputfile

По умолчанию команда extract создает файл trace.dat, но с помощью этой опции можно задать иной файл для вывода.

-s

Задает извлечение данных из буфера «моментальных снимков» (snapshot), если это поддерживается ядром.

—date

То же самое, что опция trace-cmd record —date, но с отключением всей трассировки в программе извлечения. Т. е. в конце извлечения данных выполняется что-то вроде trace-cmd reset.

-B buffer-name

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

-a

Задает извлечение данных из всех экземпляров буферов. При указании этой опции экземпляр верхнего уровня не используется, если не задана также опция -t.

-t

Задает извлечение данных из буфера верхнего уровня. Без опций -B или -a это обеспечивает принятое по умолчанию поведение, но при указании -B или -a данные из буфера верхнего уровня извлекается вместе с данными из указанных этими опциями буферов.

show

Показывает содержимое буфера трассировки ядра (ftrace).

Синтаксис

trace-cmd show [OPTIONS]

Описание

Команда trace-cmd show выводит содержимое одного из файлов трассировки (ftrace) ядра Linux — trace, snapshot или trace_pipe. Это эквивалентно использованию команд вида

cat /sys/kernel/debug/tracing/trace

Опции

-p

Задает вывод содержимого файла trace_pipe вместо выводимого по умолчанию trace, который является статическим (т. е. по завершении трассировки содержимое файла trace остается неизменным).

Чтение файла trace_pipe является поглощающим и данные не будут повторяться при следующем чтении. Файл при этом блокируется. Если в файле нет данных, trace-cmd show будет останавливаться и ждать их появления.

-s

Задает вывод содержимого файла snapshot вместо выводимого по умолчанию trace. Снимки делаются записывающим приложением и ядро будет переключаться между текущим активным буфером snapshot и следующим буфером. Без переключения файл snapshot является статическим. Считывание файла не поглощает данные из него.

-c cpu

Задает чтение файла trace лишь для указанного CPU.

-f

Выводит полный путь к отображаемому файлу.

-B buf

Если был создан экземпляр буфера, опция -B обеспечивает доступ к файлам, связанным с этим буфером.

—tracing_on

Указывает, включена ли трассировка на данном экземпляре.

—current_tracer

Показывает, что служит текущим трассировщиком.

—buffer_size

Показывает текущий размер буфера (на процессор)

—buffer_total_size

Показывает общий размер всех буферов.

—ftrace_filter

Показывает установленные фильтры функций.

—ftrace_notrace

Показывает, какие функции отключены установленными фильтрами.

—ftrace_pid

Показывает PID трассировщиков функций (если они есть).

—graph_function

Показывает функции, которые будут отображены.

—graph_notrace

Показывает функции, которые не будут отображены.

—cpumask

Показывает маску CPU, для которых будет выполняться трассировка.

options

Выводит список доступных опций для плагинов trace-cmd.

Синтаксис

trace-cmd options

Описание

Команда trace-cmd options будет проверять плагины trace-cmd, используемые командой trace-cmd report, и выводить их список.

start

Запускает трассировщик ftrace без записи в файл.

Синтаксис

trace-cmd start [OPTIONS]

Описание

Команда trace-cmd start включает всю трассировку ftrace, как это делает trace-cmd record(1), но без запуска потоков для создания файла trace.dat. Это полезно, когда нужно просто включить ftrace и интересна лишь трассировка после того, как произошло некоторое событие и до момента остановки. Затем трассировку можно считать напрямую из псевдофайловой системы ftrace или извлечь с помощью команды trace-cmd extract.

Опции

Опции этой команды совпадают с опциями trace-cmd record, за исключением относящихся к записи (-s, -o, -F, -N, -t).

stop

Команда останавливает запись трассировщика ядра Linux ftrace в кольцевой буфер

Синтаксис

trace-cmd stop

Описание

Команда trace-cmd stop служит дополнением к trace-cmd-start и будет отключать запись ftrace в кольцевой буфер, не отменяя издержек, которые могут быть связаны с трассировкой. Отключается лишь обновление кольцевого буфера, но трассировка ftrace может продолжаться, создавая издержки.

После остановки команда trace-cmd extract позволяет прочитать данные из кольцевого буфера и создать файл trace.dat. Возможно также прямое считывание данных из псевдофайловой системы.

Для полного отключения трассировки с целью устранения связанных с ней издержек служит команда trace-cmd reset, но при сбросе записанные данные будут потеряны.

Опции

-B buffer-name

Если ядро поддерживает множество буферов, эта опция позволяет остановить трассировку для определенного буфера, не воздействуя на остальные. Опцию можно указать несколько раз для разных буферов. При указании этой опции экземпляр верхнего уровня не останавливается, если не была задана также опция -t.

-a

Останавливает трассировку всех имеющихся экземпляров буферов. При указании этой опции экземпляр верхнего уровня не останавливается, если не была задана также опция -t.

-t

Останавливает буфер верхнего уровня. Без опции -B или -a эта опция обеспечивает принятое по умолчанию поведение, но при наличии -B или -a, будет останавливаться также буфер верхнего уровня.

reset

Отключает все трассировки ftrace, восстанавливая полную производительность.

Синтаксис

trace-cmd reset [OPTIONS]

Описание

Команда trace-cmd reset выключает все трассировки ftrace, возвращая полную производительность системы, которая была до включения трассировки. Это нужно делать, поскольку команды trace-cmd record, trace-cmd stop и trace-cmd extract не отключают трассировщик даже после извлечения данных из буфера. Причина этого заключается в том, что пользователь может просто захотеть включить трассировщик вручную с использованием псевдофайловой системы или проверить другие части ftrace на предмет результатов работы trace-cmd. После команды reset все данные в кольцевых буферах и установленные опции будут потеряны.

Опции

Следует отметить, что для этой команды важен порядок указания опций в командной строке (см. Примеры).

-b buffer_size

При загрузке ядра кольцевой буфер ftrace имеет минимальный размер (3 страницы на CPU). При первом использовании трассировщика кольцевой буфер расширяется до установленного значения (по умолчанию 1,4 Мбайт на CPU).

Если дальнейшей трассировки не предполагается, эта опция позволяет уменьшить кольцевой буфер, сохраняя память.

trace-cmd reset -b 1

Задает воздействие на экземпляры буфера, заданные последней опцией -B, -t или -a:

при использовании после -B, изменяет размер экземпляра буфера, предшествующего опции в командной строке;

при использовании после -a меняет размер всех экземпляров буферов, за исключением верхнего уровня;

при использовании после -t или перед -B или -a, меняет размер буфера верхнего уровня.

-B buffer-name

Если ядро поддерживает несколько буферов, эта опция будет задавать воздействие лишь на указанный в ней буфер. Опция может включаться несколько раз для разных буферов. Буфер верхнего уровня не будет сбрасываться, если не указана также опция -t.

-a

Сбрасывает трассировку для всех имеющихся экземпляров буферов. При указании этой опции экземпляр верхнего уровня не сбрасывается, если не была задана также опция -t.

-d

Эта опция удаляет экземпляры буферов, заданные последними опциями -B или -a. Поскольку буфер верхнего уровня не может быть удален, эту опцию нельзя указывать после опции -t или перед опцией -B или -a в командной строке.

-t

Сбрасывает экземпляр буфер верхнего уровня. Без опции -B или -a эта опция обеспечивает принятое по умолчанию поведение, но при наличии -B или -a, будет сбрасываться также буфер верхнего уровня.

Примеры

Для сброса трассировки в instance-one и установки размера буфера 4096 Кбайт на процессор, а также удаления instance-two служит приведенная ниже команда. Экземпляр верхнего уровня и другие буферы сохраняются.

trace-cmd reset -B instance-one -b 4096 -B instance-two -d

Для удаления всех экземпляров кроме буфера верхнего уровня служит приведенная ниже команда.

trace-cmd reset -a -d

Для удаления всех экземпляров и буфера верхнего уровня служит команда

trace-cmd reset -t -a -d

Приведенная ниже команда неверна, поскольку она пытается удалить экземпляр верхнего уровня.

trace-cmd reset -a -t -d

Для сброса экземпляра верхнего уровня и установки размера буфера 1024 Кбайт на процессор служит приведенная ниже команда. На другие буферы она не воздействует.

trace-cmd reset -b 1024

split

Расщепляет файл trace.dat на более мелкие файлы.

Синтаксис

trace-cmd split [OPTIONS] [start-time [end-time]]

Описание

Команда trace-cmd служит для разбиения trace.dat на более мелкие файлы. Параметр start-time указывает время, с которого начнется новый файл. Команду trace-cmd report и копирование временной метки определенного события можно использовать в качестве start-time или end-time. Расщепление прекратит создание файлов по достижении времени end-time. Если нужно лишь время окончания, в качестве start-time служит 0.0.

Если параметр start-time опущен, расщепление начинается с начала файла. Если опущен параметр end-time, расщепление будет продолжаться до конца файла, если его не остановят другие опции.

Опции

-i file

Если эта опция не задана, команда будет расщеплять файл trace.dat. С помощью опции можно указать иной файл.

-o file

По умолчанию команда split будет использовать имя входного файла в качестве основы для имен создаваемых файлов, добавляя к входному имени суффиксы вида .# (trace.dat.1, trace.dat.2 и т. п.). Данная опция позволяет изменить базовое имя файлов. Например, -o приведет к созданию файлов file.1, file.2 и т. д.

-s seconds

Задает продолжительность времени (в секундах), по истечении которого запись в файл следует остановить и начать следующий.

-m milliseconds

Задает продолжительность времени (в миллисекундах), по истечении которого запись в файл следует остановить и начать следующий.

-u microseconds

Задает продолжительность времени (в микросекундах), по истечении которого запись в файл следует остановить и начать следующий.

-e events

Задает число событий, записываемых в файл прежде, чем начать новый.

-p pages

Задает число страниц, записываемых в файл прежде, чем начать новый.

Примечание. Опции -p, -e, -u, -m и -s являются взаимоисключающими, т. е. не может присутствовать более одной из них.

При установке опции -p автоматически добавляется опция -c.

-r

Эта опция заставляет повторять разбиение, пока не будет достигнуто значение end-time (или конец файла при отсутствии end-time).

trace-cmd split -r -e 10000

Будет разбивать trace.dat на файлы, содержащие не более 10000 событий в каждом.

-c

Эта опция приводит к разбиению файла по процессорам.

trace-cmd split -c -p 10

будет создавать файл, имеющий 10 страниц на каждый CPU.

-C cpu

Эта опция будет обеспечивать расщепление для одного CPU, извлекая из файла лишь данные, соответствующие параметру cpu.

trace-cmd split -C 1

будет выделять в файл все события для cpu 1.

list

Выводит список доступных плагинов, событий и опций ftrace.

Синтаксис

trace-cmd list [OPTIONS]

Описание

Команда trace-cmd list выводит список доступных плагинов, событий и опций ftrace, которые настроены на текущей машине. Если команда используется без опций, выводятся все плагины, события и опции ftrace на стандартный вывод.

Опции

-e [regex]

Эта опция задает вывод всех доступных событий, разрешенных на локальной машине. Она может принимать в качестве дополнительного аргумента регулярное выражение, соответствующее regcomp, для поиска событий.

trace-cmd list -e '^sys.*'

-F

Применяется вместе с -e regex для вывода форматов событий.

-l

Применяется вместе с -e regex для вывода фильтров событий.

-R

Применяется вместе с -e regex для вывода триггеров событий.

-t

Обеспечивает вывод списка доступных трассировщиков, разрешенных на локальной системе.

-p

Совпадает с -t и применяется для унаследованных систем.

-o

Обеспечивает вывод списка доступных опций ftrace, настроенных на локальной системе.

-f [regex]

Обеспечивает вывод всех доступных функций фильтрации. Это будет список функций системы, которые можно трассировать или фильтровать. Опция может принимать в качестве дополнительного аргумента регулярное выражение, соответствующее regcomp, для поиска функций.

trace-cmd list -f '^sched.*'

-P

Обеспечивает вывод списка файлов плагинов, загружаемых trace-cmd report.

-O

Обеспечивает вывод списка опций плагинов, которые могут применяться в команде trace-cmd report -O option.

-B

Выводит список экземпляров буферов.

-C

Выводит список часов, которые могут применяться в команде trace-cmd record -C. Активные часы указываются в квадратных скобках [].

listen

Задает прослушивание входящих соединений для записи трассировки.

Синтаксис

trace-cmd listen -p port [OPTIONS]

Описание

Команда trace-cmd listen активизирует порт для прослушивания входящих соединений от других хостов, на которых используется команда trace-cmd record с опцией -N. Когда соединение организовано, удаленный хост будет передавать через него данные, которые будут сохраняться в файле с именем trace.HOST:PORT.dat (HOST — имя удаленного хоста, PORT -номер порта, используемый удаленным хостом для соединения).

Опции

-p port

Эта опция задает порт для прослушивания входящих соединений.

-D

Эта опция переводит trace-cmd listen в режим демона.

-d dir

Эта опция задает каталог для записи файлов данных.

-o filename

Эта опция заменяет принятую по умолчанию запись в файл trace.HOST:PORT.dat записью в указанный файл.

-l filename

Эта опция задает запись выходных сообщений в указанный файл вместо стандартного вывода.

restore

Восстанавливает отказавшую запись трассировки.

Синтаксис

trace-cmd restore [OPTIONS] [command] cpu-file [cpu-file …]

Описание

Команда trace-cmd restore восстанавливает файл после отказа trace-cmd record. Если при работе trace-cmd record возникает отказ, программа оставляет файлы данных для отдельных процессоров, не создавая финального файла trace.dat. Команда trace-cmd restore будет собирать эти файлы для создания рабочего файла trace.dat, который может быть прочитан командой trace-cmd-report.

При работе команды trace-cmd record она запускает отдельный процесс для каждого CPU и записывает для них файлы данных, обычно называемые trace.dat.cpuX, где X указывает номер процессора. Если для команды trace-cmd record использовалась опция -o, файлы данных CPU будут иметь другие имена вместо trace.dat. При возникновении отказа до завершения трассировки файлы отдельных CPU сохраняются, но файла trace.dat не будет. Команда trace-cmd restore создает trace.dat из имеющихся файлов данных.

Опции

-c

Задает создание частичного файла trace.dat для машины, который можно потом использовать в команде trace-cmd restore. Эта опция полезна для встраиваемых систем. Если сервер содержит файлы отдельных процессоров отказавшей команды trace-cmd record (или trace-cmd listen), trace-cmd restore можно запустить на встраиваемом устройстве с опцией -c для получения всех данных этого встраиваемого устройства. Затем созданный файл копируется на сервер для запуска команды trace-cmd restore.

Если опция -o не задана, создается файл trace-partial.dat. Это связано с тем, что файл не будет полной версией, пригодной для использования в trace-cmd report.

-t tracing_dir

При использовании вместе с опцией -c переопределяет место для считывания данных о событиях. По умолчанию данные трассировки считываются из каталога debugfs/tracing, но опция -t позволяет указать иное место. Это может быть полезно при создании файла trace.dat с другой машины.

-k kallsyms

При использовании вместе с опцией -c переопределяет место для считывания данных kallsyms. По умолчанию используется /proc/kallsyms, но опция -k позволяет указать иное место. Это может быть полезно при создании файла trace.dat с другой машины.

-o output

По умолчанию trace-cmd restore будет создавать файл trace.dat (или trace-partial.dat при наличии опции -c), но опция -o позволяет указать другой файл.

-i input

По умолчанию trace-cmd restore читает информацию текущей системы для создания начальных данных, хранящихся в файле trace.dat. Если отказ произошел на другой машине, на ней следует запустить команду trace-cmd с опцией -c для создания частичного файла trace.dat. Затем этот файл копируется на машину, где используется команда trace-cmd restore с опцией -i для загрузки данных из файла вместо считывания из локальной системы.

Примеры

Если отказ произошел на другой машине, можно воспользоваться командой

$ trace-cmd restore -c -o box-partial.dat

Затем на сервер, где размещены файлы данных cpu используется команда

$ trace-cmd restore -i box-partial.dat trace.dat.cpu0 trace.dat.cpu1

Это позволяет восстановить файл trace.dat для встраиваемого устройства.

stack

Читает, включает или отключает трассировку ядра Linux ftrace.

Синтаксис

trace-cmd stack

Описание

Команда trace-cmd stack включает трассировщик стека в ядре, который включает трассировщик функций и при каждом вызове функции в ядре проверяется стек. При обнаружении нового максимума использования стека это записывается.

При отсутствии опции отображается текущий стек.

Для включения трассировщика стека используется опция —start, для отключения — —stop. Выводиться будет максимальный стек, найденный с момента старта.

Для сброса счетчика стека служит опция —reset.

check-events

Анализирует форматы событий в локальной системе.

Синтаксис

trace-cmd check-events [OPTIONS]

Описание

Команда trace-cmd check-events разбирает строки форматов для всех событий в локальной системе. Она возвращает информацию о возможности корректного анализа каждого формата. Если явно не указано иное, команда будет загружать плагины.

Эта команда полезна для проверки всех строк формата трассировки, которые могут включать внутренние функции ядра, не декодируемые вне ядра. Это может означать необходимость изменения необработанных строк формата или создания плагина для их анализа.

Опции

-N

Отменяет загрузку плагинов.

stream

Направляет трассировку в stdout.

Синтаксис

trace-cmd stream [OPTIONS] [command]

Описание

Команда trace-cmd запускает трассировку подобно trace-cmd record, но не выводит данные в файл, а считывает их напрямую из двоичного буфера, преобразуя в понятный человеку формат и выводит на stdout.

В основном это совпадает с командой trace-cmd start и последующей командой trace-cmd show с опцией -p. Команда trace-cmd stream не так эффективна как чтение из канала, поскольку большая часть потока выполняется в пользовательском пространстве. Эта команда полезна в тех случаях. Когда нужно выполнить основную работу в пользовательском пространстве, а не в ядре, а также помогает отлаживать команды trace-cmd profile, использующие код потока для анализа данных профиля в реальном масштабе времени.

Опции

Опции команды совпадают с опциями trace-cmd record за исключением -o.

snapshot

Принимает, сбрасывает, освобождает и выводит моментальные снимки трассировки ftrace (snapshot).

Синтаксис

trace-cmd snapshot [OPTIONS]

Описание

Команда trace-cmd snapshot управляет или показывает моментальный снимок трассировки ftrace (если ядро поддерживает это). Она полезна для «замораживания» экземпляра трассировки без остановки процесса.

           trace-cmd start -p function 
           trace-cmd snapshot -s 
           trace-cmd snapshot 
          [ выводит содержимое буфера в момент trace-cmd snapshot -s ] 
           trace-cmd snapshot -s 
           trace-cmd snapshot 
          [ выводит новое содержимое буфера при последней операции -s ]

Опции

-s

Делает моментальный снимок работающего буфера.

-r

Очищает буфер.

-f

Освобождает буфер моментальных снимков, использующий память ядра. Неиспользуемые буферы лучше освобождать. Первая опция -s будет выделять буфер, если он еще не создан.

-c cpu

Задает вывод моментального снимка для отдельного процессора (может поддерживаться ядром не полностью)

-B buf

Если экземпляр буфер создан, опция -B будет работать со снимком в этом буфере.

Формат файла trace-cmd.dat

Описание

Утилита trace-cmd создает файл trace.dat. Этот файл может иметь другое имя, если пользователь указал его, но в любом случае он будет иметь некий двоичный формат. Файл применяется программой trace-cmd для хранения трассировок ядра с возможностью извлечения данных (см. report).

Начальный формат

Первые три байта файла содержат «магическое значение»

0x17 0x08  0x44

В следующий 7 байтах содержится строка

tracing

Далее следует строка символов с завершающим \0, указывающая версию файла. Например,

"6\0"

Следующий байт указывает тип значений

          0 = little endian 
          1 = big endian

Далее следует байт, указывающий размер значения типа long

          4 — 32-битовые значения long
          8 - 64-битовые значения long

Примечание. Этот размер long предназначен для пользовательского пространства и не связан с размером в ядре.

Далее все числа указываются в зависимости от заданного порядка байтов (endianess).

Следующие 4 байта образуют 32-битовое слово, определяющее размер страницы на трассируемом хосте.

Формат данных заголовка

Сразу после начального формата следуют данные о заголовках трассировки, записанные от целевого устройства.

Следующие 12 байтов содержат строку

header_page\0

Затем следуют 8 байтов, образующих 64-битовое слово размера данных заголовка страницы, которая храниться далее.

Следующий блок данных имеет размер, указанный в предыдущих 8 байтах и содержит данные из debugfs/tracing/events/header_page.

Примечание. Размер второго поля commit содержит размер long в целевом ядре. Например,

field: local_t commit;        offset:8;       \fBsize:8;\fR   signed:1;

указывает, что в ядре используются 64-битовые значения long.

Следующие 13 байтов содержат строку

header_event\0

Затем следуют 8 байтов, образующих 64-битовое слово размера заголовка данных событий, хранящегося далее.

Следующий блок, размер которого указан предыдущими 8 байтами, содержит данные из debugfs/tracing/events/header_event.

Эти данные позволяют trace-cmd узнать о наличии каких-либо изменений в кольцевом буфере ядра.

Формат событий ftrace

Сразу после заголовка следует информация о конкретных событиях трассировки, которые используются плагинами ftrace plugins и не включены трассировкой событий.

Первые 4 байта содержат 32-битовое слово числа файлов формата событий ftrace, сохраненных в файле.

Для числа вхождений, указанного предыдущими 4 байтами, 8 байтов указывают размер файла формата событий ftrace. Файл формата событий ftrace копируется с целевой машины

debugfs/tracing/events/ftrace/<event>/format

Формат событий

Сразу после форматов ftrace размещается информация о схеме событий.

Первые 4 байта содержат 32-битовое слово числа систем событий, хранящихся в файле. Это каталоги в структуре debugfs/tracing/events за исключением каталога ftrace.

Для числа вхождений, указанного предыдущими 4 байтами, указывается строка с null-символом в конце, задающая имя системы, 4 байта 32-битового слова числа событий в системе.

Для числа вхождений, указанного предыдущими 4 байтами, 8 байтов указывают размер файла формата событий.

Файл формата событий ftrace копируется с целевой машины

debugfs/tracing/events/<system>/<event>/format

Информация KALLSYMS

Сразу за форматами событий следуют данные отображения имен функций на их адреса.

Первые 4 байта содержат 32-битовое слово размера данных об отображении функций.

Следующий блок, размер которого определен предыдущими 4 байтами, содержит данные из файла целевой машины

/proc/kallsyms

Информация TRACE_PRINTK

Если разработчики применяли в ядре trace_printk(), можно сохранять строку формата вне кольцевого буфера, в файле

debugfs/tracing/printk_formats

Следующие 4 байта содержат 32-битовое слово размера данных, хранящихся в формате printk.

Далее следует блок, размер которого задан предыдущими 4 байтами, с данными из debugfs/tracing/printk_formats.

Данные процессов

Сразу после форматов trace_printk следуют данные отображения PID на имена процессов.

Следующие 8 содержат 64-битовое слово размера данных отображения PID на имена процессов.

Далее следует блок, размер которого задан предыдущими 8 байтами, с данными из debugfs/tracing/saved_cmdlines.

Остальная часть заголовка TRACE-CMD

Сразу после данных о процессах следует последний бит заголовка trace.dat.

Следующие 4 байта содержат 32-битовое слово числа CPU, обнаруженных на целевой машине (и имеющих данные трассировки).

Следующие 10 байтов содержат одну из строк

options  \0 
latency  \0 
flyrecord\0

Для случая options \0 следующие 2 байта содержат 16-битовое слово, задающее текущие опции (0 — больше нет опций).

В остальных случаях следующие 4 байта содержат 32-битовое слово размера опций. Если читающая сторона не понимает опцию, она может пропустить ее. В настоящее время опции не определены, но здесь могут быть расширения данных.

Следующая опция размещается сразу за предыдущей и опции завершаются 0 в поле типа опции.

Следующие 10 байтов содержат одну из строк

latency  \0 
flyrecord\0

которые были бы и при отсутствии опций.

Для случая latency \0, остальная часть файла представляет просто текст ASCII из файла целевой системы

debugfs/tracing/trace

Для случая flyrecord\0 далее следует представленная ниже информация.

Для числа CPU, определенного раньше указывается:

8 байтов 64-битового слова, указывающего смещение в файле, где хранятся данные для CPU;

8 байтов 64-битового слова, указывающего размер данных CPU, расположенных по этому смещению.

Данные CPU

Данные процессоров хранятся в части файла, указанной в конце заголовка. Между заголовком и данными CPU помещается заполнение, для выравнивания данных CPU по краю страницы (страница цели) в файле.

Эти данные копируются напрямую из кольцевого буфера трассировки в том формате, который задан заголовком события, включенным в формат заголовка файла.

Программа trace-cmd будет пытаться выполнить mmap для данных страница за страницей с размером страниц целевой системы, если это возможно. При отказе mmap будут просто считываться данные.

Рубрика: Linux, Измерения и тестирование | Комментарии к записи trace-cmd — программа для работы с ftrace отключены

Трассировщик функций ftrace

Трассировщик функций ftrace

PDF

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

Хотя ftrace обычно считают трассировщиком функций, реально это целый набор средств трассировки, включающий отслеживание задержки для просмотра событий между отключением и включением прерываний, при вытеснении задачи или с момента ее пробуждения до фактического планирования.

Одним из наиболее распространенных применений ftrace является отслеживание событий. В ядре имеются сотни статических событий, которые могут быть включены через файловую систему tracefs для просмотра происходящего в отдельных частях ядра.

Дополнительную информацию о событиях можно найти в файле events.txt
документации ядра.

Детали реализации трассировщика описаны в файле ftrace-design.

Файловая система

Ftrace использует файловую систему tracefs для хранения управляющих файлов и данных.

При настройке tracefs в ядре (выбор любой из опций ftrace) создается каталог /sys/kernel/tracing. Для автоматического монтирования этого каталога можно добавить в файл /etc/fstab команду

tracefs	/sys/kernel/tracing	tracefs defaults	0	0

Можно монтировать файловую систему по мере надобности с помощью команды

mount -t tracefs nodev /sys/kernel/tracing

Для быстрого доступа к каталогу можно создать символьную ссылку

ln -s /sys/kernel/tracing /tracing

Примечание. До версии ядра 4.1 управление трассировкой происходило в рамках файловой системы debugfs, обычно называемой /sys/kernel/debug/tracing. Для совместимости с прежними версиями при монтировании файловой системы debugfs автоматически монтируется система tracefs как /sys/kernel/debug/tracing1.

Все файлы системы tracefs доступны и в файловой системе debugfs.

Все выбранные опции ftrace будут отражаться и в файловой системе tracefs. Далее в документе предполагается текущим каталог ftrace (cd /sys/kernel/tracing) и файлы будут именоваться относительно этого каталога без указания полного пути /sys/kernel/tracing.

Исходя из того, что настройка ftrace в ядре присутствует, после монтирования tracefs вы получите доступ к управлению и выходным файлам ftrace. Ниже описаны некоторые из этих файлов.

current_tracer

Указывает текущий настроенный трассировщик.

available_tracers

Содержит список трассировщиков, включенных в ядре. Эти трассировщики можно настраивать, помещая имя нужного трассировщика с помощью команды echo в файл current_tracer.

tracing_on

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

Функция ядра tracing_off() может применяться внутри ядра для отключения записи в кольцевой буфер, помещая 0 в указанный файл. Можно восстановить запись из пользовательского пространства, отправив в файл значение 1.

Отметим, что функция и триггер событий traceoff также будут помещать в файл значение 0 и останавливать запись. Для восстановления записи служит указанный выше способ записи значения 1 в файл.

trace

В этот файл записывается вывод трассировки в понятном человеку формате (см. ниже). Отметим, что трассировка приостанавливается при чтении этого файла (open).

trace_pipe

Вывод в этот файл такой же как в trace, но файл предназначен для потоковой трассировки. Чтение из файла блокируется на время записи новых данных. В отличие от trace, этот файл является «потребителем» — считывание из этого файла «потребляет» данные и они уже не будут видны при последующих обращениях. Файл trace является «статическим» и если трассировщик не добавляет в него данных, при каждом обращении будет считываться одна и та же информация. При считывании файла trace_pipe трассировка не отключается.

trace_options

Этот файл позволяет пользователю контролировать объем данных, отображаемых в одном из указанных выше выходных файлов. Имеются также опции для изменения режима работы трассировщика и событий (трассировка стека, временные метки и . п.).

options

В этом каталоге расположены файлы для каждой доступной опции трассировки (те же, что в trace_options). Опции могут быть включены и отключены записью 1 или 0 (соответственно) в файл с именем опции.

tracing_max_latency

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

tracing_thresh

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

buffer_size_kb

Размер буфера для каждого CPU в килобайтах. По умолчанию буферы трассировки имеют одинаковый размер для всех процессоров. Буферы трассировки выделяются страницами (блоками памяти, используемыми ядром; размер страницы обычно составляет 4 килобайта). Если последняя выделенная страница имеет размер больше запрошенного, реальный буфер будет использовать все пространство, а не то, которое запрошено и отображается. Отметим, что размер буферов не обязан быть кратным размеру страницы из-за метаданных управления буферами.

Размеры буферов для отдельных CPU могут различаться (см. per_cpu/cpu0/buffer_size_kb ниже) и в этом случае файл будет содержать значение X.

buffer_total_size_kb

Общий размер буферов трассировки в килобайтах.

free_buffer

Если процесс выполняет трассировку и кольцевой буфер нужно «освободить» после завершения процесса, даже если процесс уничтожен по сигналу, для освобождения буфера можно использовать этот файл. При закрытии данного файла размер кольцевого буфера снижается до минимального. Выполняющий трассировку процесс открывает этот файл и при завершении процесса дескриптор файла будет освобождаться. В результате файл будет закрыт и кольцевой буфер «освободится».

При установке опции disable_on_free трассировка будет останавливаться.

tracing_cpumask

Маска, позволяющая пользователю задать трассировку лишь для нужных CPU. Маска указывается в шестнадцатеричном формате.

set_ftrace_filter

При динамической трассировке (см. dynamic ftrace ниже) код динамически изменяется для запрета вызова профилировщика функций (mcount). Это позволяет выполнить трассировку практически без влияния на производительность. Однако имеется побочное влияние на включение или отключение трассировки определенных функций. Отправка (echo) имен функций в этот файл ограничивает трассировку лишь включенными в список функциями. Это влияет на трассировщики function и function_graph, а также на профилировку функций (см. function_profile_enabled).

Функции, перечисленные в файле available_filter_functions могут быть записаны в файл фильтров.

Этот интерфейс можно использовать также для команд (см. Команды фильтрации).

set_ftrace_notrace

Это антипод set_ftrace_filter и любая функция, добавленная в файл, не будет трассироваться. При указании функции в set_ftrace_filter и set_ftrace_notrace трассировка этой функции выполняться не будет.

set_ftrace_pid

Указывает трассировщику function отслеживать лишь функции с PID, указанным в этом файле.

Если установлена опция function-fork, при ветвлении задачи с указанным в этом файле PID, значения PID дочерних процессов будут автоматически добавляться в этот файл и дочерние процессы также будут отслеживаться. При завершении задачи PID удаляется из файла.

set_event_pid

Задает
трассировку событий лишь для процессов,
PID указан
в этом файле
.

Отметим,
что
sched_switch и sched_wake_up также будут отслеживать события, указанные в этом файле.

Для добавления в файл PID дочерних процессов при ветвлении следует включить опцию event-fork (по завершении процесса PID будет удаляться из файла).

set_graph_function

Функции, указанные в этом файле и вызванные ими функции, будут отслеживаться трассировщиком function_ graph (см. Динамическая трассировка ftrace). Отметим, что set_ftrace_filter и set_ftrace_notrace сохраняют влияние на набор отслеживаемых функций.

set_graph_notrace

Похожа на set_graph_function, но отключает трассировщик function_graph до выхода из указанной в этом файле функции. Это позволяет пропустить трассировку функций, вызываемых из заданной функции.

available_filter_functions

Этот файл содержит список функций, для которых возможна трассировка, указанных по именам. Эти функции можно передать в опции (файлы) set_ftrace_filter, set_ftrace_notrace, set_graph_function и set_graph_notrace для управления их трассировкой (см. Динамическая трассировка ftrace)

dyn_ftrace_total_info

Этот файл служит для отладки и указывает число функций, которые были преобразованы в nop и доступны для трассировки.

enabled_functions

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

Если обратный вызов зарегистрирован для трассировки функцией с атрибутом сохранения регистров (save regs), что ведет к добавочному росту издержек, в строке возвращающей регистры функции будет выводиться символ R.

Если обратный вызов зарегистрирован для трассировки функцией с атрибутом ip modify (т. е. regs->ip можно изменить), в строке с функцией, которая может быть переопределена, выводится символ I.

Если архитектура позволяет, будет также показано, для каких callback возможен прямой вызов из функции. Если значение счетчика больше 1, это скорей всего будет ftrace_ops_list_func().

Если обратный вызов функции имеет переход к trampoline2, специфичному для callback, а не к стандартному trampoline, будет выводиться адрес перехода, а также функция, которую вызывает trampoline.

function_profile_enabled

При установке включает отслеживание всех функций с помощью трассировщика function или (если настроен) function_graph. Будет сохраняться гистограмма числа вызовов функций, а при настроенном трассировщике function_graph — еще и время, проведенное в этих функциях. Содержимое гистограммы размещается в файлах по процессорам trace_stat/function<cpu> (function0, function1 и т. д.).

trace_stat

Каталог, в котором хранится статистика трассировки.

kprobe_events

Включает точки динамической трассировки (см. файл kprobetrace.txt в документации ядра).

kprobe_profile

Статистика точек динамической трассировки (см. файл kprobetrace.txt в документации ядра).

max_graph_depth

Применяется с трассировщиком function_graph, задавая максимальную глубину трассировки внутрь функции. При установке в файле значения 1 будет показываться только первый вызов функции ядра из пользовательского пространства.

printk_formats

Этот файл служит для инструментов, читающих необработанные (raw) файлы. Если событие в кольцевом буфере указывается строкой, в буфер записывается лишь указатель, а не сама строка. Это не позволяет инструментам узнать, что было в строке. Данный файл отображает строки и адреса, позволяя инструментам сопоставлять указатели со строками.

saved_cmdlines

В трек событий записывается лишь pid задачи, если событие специально не сохраняет и команду. Ftrace кэширует отображения pid на команды, чтобы попытаться указать для событий и команду. Если pid для команды не указа, выводится <…>.

Если для опции record-cmd установлено значение 0, команды задач не сохраняются при записи. По умолчанию сохранение включено.

saved_cmdlines_size

По умолчанию сохраняется 128 команд (см. saved_cmdlines выше). Для изменения числа кэшируемых команд в этот файл записывается соответствующее число.

saved_tgids

При установленной опции record-tgid для каждого запланированного переключения контекста сохраняется идентификатор группы (Task Group ID) для задачи в таблице сопоставления PID потока с TGID. По умолчанию опция record-tgid выключена.

snapshot

Показывает «моментальный снимок» (snapshot) буфера и позволяет пользователю сделать снимок текущей трассировки (см. раздел Мгновенные снимки).

stack_max_size

При активизации трассировщика стека здесь будет указан максимальный наблюдаемый размер стека (см. раздел Трассировка стека).

stack_trace

Здесь указывается обратная трассировка наибольшего стека, который встретился при активизации трассировщика стека (см. раздел Трассировка стека).

stack_trace_filter

Похоже на set_ftrace_filter, но ограничивает функции, которые будет проверять трассировщик стека.

trace_clock

При записи события в кольцевой буфер указывается временная метка, которая берется из определенных часов. По умолчанию ftrace использует локальные часы (local). Это очень быстрые часы, привязанные к каждому процессору, но они могут быть не синхронизированы между разными CPU.

	  # cat trace_clock
	  [local] global counter x86-tsc

Используемые часы указываются в квадратных скобках.

local

Используемые по умолчанию часы, которые могут быть не синхронизированы между CPU.

global

Эти часы синхронизированы на всех CPU, но могут быть медленней часов local.

counter

Это не часы, а счетчик, увеличивающий значение на 1 и синхронизированный со всеми CPU. Счетчик может быть полезен, когда нужно знать точный порядок событий, связанных с разными CPU.

uptime

Это счетчик циклов jiffy и временная метка относительно момента последней загрузки системы.

perf

Задает для ftrace использование тех же часов, которые применяются perf. В конечном счете perf сможет считывать буферы ftrace и это поможет при чередовании данных.

x86-tsc

Архитектура может задавать свои часы. Например, в x86 применяются часы TSC.

ppc-tb

Значение регистра timebase в powerpc. Оно синхронизировано для всех CPU и может служить для сопоставления событий между гипервизором и гостевыми системами, если известно значение tb_offset.

mono

Быстрый, монотонно возрастающий счетчик (CLOCK_MONOTONIC), согласуемый с NTP .

mono_raw

Быстрый, монотонно возрастающий счетчик (CLOCK_MONOTONIC_RAW) без возможности согласования частоты, работающий от аппаратного генератора сигналов.

boot

Загрузочные часы (CLOCK_BOOTTIME) на основе быстрого монотонно возрастающего счетчика, учитывающие время ожидания. Поскольку доступ к этим часам рассчитан на использование при трассировке на пути с остановками, возможны побочные эффекты при доступе к часам после того, как было учтено время приостановки до обновления монотонно возрастающего счетчика. В 32-битовых системах 64-битовое смещение загрузки может обновляться частично. Эти эффекты возникают редко и постобработка может справляться с ними (см. комментарии в функции ядра ktime_get_boot_fast_ns()).

Для выбора часов просто помещается их имя в файл trace_clock

	  # echo global > trace_clock

trace_marker

Этот файл очень полезен для синхронизации пользовательского пространства с событиями в ядре. Запись строки в этот файл копируется в буфер трассировки ftrace.

Полезно открыть этот файл в приложении при его запуске и просто сослаться на дескриптор файла

		void trace_write(const char *fmt, ...)
		{
			va_list ap;
			char buf[256];
			int n;

			if (trace_fd < 0)
				return;

			va_start(ap, fmt);
			n = vsnprintf(buf, 256, fmt, ap);
			va_end(ap);

			write(trace_fd, buf, n);
		}

	start::

		trace_fd = open("trace_marker", WR_ONLY);

Примечание. Запись в файл trace_marker будет также вызывать запись в /sys/kernel/tracing/events/ftrace/print/trigger (см. Event triggers в файле Documentation/trace/events.rst и пример в разделе 3 файла trace/histogram.rst)

trace_marker_raw

Похож на trace_marker, но предназначен для записи двоичных данных, когда можно использовать инструмент для анализа.

uprobe_events

Добавляет в программу динамические точки трассировки (см. uprobetracer.txt).

uprobe_profile

Статистика uprobe (см. uprobetracer.txt).

instances

Это способ создания множества буферов трассировки, куда могут записываться разные события (см. Экземпляры).

events

Это каталог событий трассировки, в котором хранятся события точек трассировки (статические точки трассировки), встроенных в ядро. Это показывает наличие точек трассировки и их группировку в системе. Здесь расположены файлы «разрешения» для различных уровней, которые позволяют включить точки трассировки при записи 1 в соответствующий файл (см. events.txt).

set_event

Запись события в этот файл будет разрешать трассировку этого события (см. events.txt).

available_events

Список событий, трассировка которых может быть включена (см. events.txt).

timestamp_mode

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

	  # cat timestamp_mode
	  [delta] absolute

В квадратных скобках указывается действующий режим временных меток.

delta

Указывается интервал времени от предшествующего события в данном буфере. Применяется по умолчанию.

absolute

Временная метка содержит полное время, а не приращение от предыдущего значения. Эти метки занимают больше места и менее эффективны.

hwlat_detector

Каталог для детектора задержек в оборудовании (см. Определение аппаратной задержки).

per_cpu

Каталог с данными трассировки для каждого процессора. В качестве примера показан процессор 0.

per_cpu/cpu0/buffer_size_kb

Размер буфера ftrace для данного процессора. Отдельные буферы позволяют каждому процессору записывать данные самостоятельно без общего кэширования. Буферы разных процессоров могут различаться по размеру. Этот файл поход на buffer_size_kb file, но показывает размер буфера отдельного процессора.

per_cpu/cpu0/trace

Похож на файл trace, но отображает данные лишь для одного CPU. При записи очищается буфер только данного CPU.

per_cpu/cpu0/trace_pipe

Похож на trace_pipe и «потребляет» данные при чтении, но отображает (и потребляет) данные лишь одного CPU.

per_cpu/cpu0/trace_pipe_raw

Для инструментов, понимающих двоичный формат кольцевого буфера ftrace, файл trace_pipe_raw может служить для извлечения информации напрямую из кольцевого буфера. С помощью системного вызова splice() данные из буфера можно быстро перенести в файл или сеть для сбора на сервере.

Подобно trace_pipe, это потребляющий считыватель, где каждое чтение будет возвращать новые данные.

per_cpu/cpu0/snapshot

Похож на файл snapshot, но дает снимок только для одного CPU (если это поддерживается). При записи в файл очищается только буфер данного CPU.

per_cpu/cpu0/snapshot_raw

Похож на trace_pipe_raw, но считывает двоичные данные лишь из «моментального снимка» для данного CPU.

per_cpu/cpu0/stats

Статистика из кольцевого буфера процессора.

entries

Число событий, остающихся в буфере.

overrun

Число перезаписанных событий в результате заполнения буфера.

commit overrun

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

bytes

Число реально прочитанных байтов (не перезаписанных).

oldest event ts

Временная метка самого старого события в буфере.

now ts

Текущая временная метка.

dropped events

События, потерянные в результате выключения опции перезаписи.

read events

Число
считываний событий
.

Трассировщики

Ниже приведен список трассировщиков, которые могут быть настроены в системе.

function

Трассировщик
вызовов для всех функций ядра.

function_graph

Похож на трассировщик function, но отличается дополнительным отслеживанием выхода из функции, которое первый не выполняет. Это позволяет построить граф вызовов функций, похожий на исходный код языка C.

blk

Трассировщик блоков, применяемый пользовательским приложением blktrace.

hwlat

Трассировщик аппаратной задержки, служащий для обнаружения задержки в оборудовании. (см. Определение аппаратной задержки).

irqsoff

Трассирует области, где запрещены прерывания и сохраняет вызов с самой большой максимальной задержкой, заменяя имеющееся значение, если новый максимум превышает его. Лучше всего использовать эту трассировку со включенной опцией latency-format, которая автоматически включается при выборе трассировщика.

Этот трассировщик похож на preemptirqsoff,
но отслеживает
лишь максимальный интервал запрета
прерываний
.

preemptoff

Похож на трассировщик preemptirqsoff,
но отслеживает
лишь максимальный интервал запрета
вытеснения
.

preemptirqsoff

Похож на irqsoff и preemptoff, но трассирует и записывает лишь наибольшее время, когда irq и/или вытеснение были отключены.

wakeup

Трассировка максимальной задержки между пробуждением процесса с наивысшим приоритетом и запланированным его использованием.

wakeup_rt

Трассировка максимальной задержки между пробуждением процесса с наивысшим приоритетом и запланированным его использованием. Этот трассировщик отслеживает лишь задачи, работающие в режиме реального времени (RT3), а задачи SCHED_OTHER игнорируются.

wakeup_dl

Отслеживает и записывает максимальную задержку для задач SCHED_DEADLINE (подобно wakeup и wakeup_rt).

mmiotrace

Специальный трассировщик, служащий для отслеживания двоичных модулей. Он будет отслеживать все вызовы, которые модуль делает для оборудования.

branch

Этот трассировщик можно настроит на вероятные и маловероятные вызовы внутри ядра. Он будет отслеживать вероятные и маловероятные ветвления и оценивать корректность их предсказания.

nop

Отключает трассировку. Для выключения всех трассировщиков достаточно просто записать nop в файл current_tracer.

Примеры использования трассировщиков

Здесь представлены типовые примеры использования трассировщиков с управлением лишь через интерфейс tracefs (без утилит пользовательского пространства).

Выходной формат

Ниже представлен пример выходного формата файла трассировки (trace).

  # tracer: function
  #
  # entries-in-buffer/entries-written: 140080/250280   #P:4
  #
  #                              _-----=> irqs-off
  #                             / _----=> need-resched
  #                            | / _---=> hardirq/softirq
  #                            || / _--=> preempt-depth
  #                            ||| /     delay
  #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
  #              | |       |   ||||       |         |
              bash-1977  [000] .... 17284.993652: sys_close <-system_call_fastpath
              bash-1977  [000] .... 17284.993653: __close_fd <-sys_close
              bash-1977  [000] .... 17284.993653: _raw_spin_lock <-__close_fd
              sshd-1974  [003] .... 17284.993653: __srcu_read_unlock <-fsnotify
              bash-1977  [000] .... 17284.993654: add_preempt_count <-_raw_spin_lock
              bash-1977  [000] ...1 17284.993655: _raw_spin_unlock <-__close_fd
              bash-1977  [000] ...1 17284.993656: sub_preempt_count <-_raw_spin_unlock
              bash-1977  [000] .... 17284.993657: filp_close <-__close_fd
              bash-1977  [000] .... 17284.993657: dnotify_flush <-filp_close
              sshd-1974  [003] .... 17284.993658: sys_select <-system_call_fastpath
              ....

Заголовок выводится с именем трассировщика (в примере function). Затем выводится число событий в буфере и общее число сделанных записей. Разница между этими значениями показывает число потерянных событий (250280 — 140080 = 110200 потерянных событий).

В заголовке разъясняется содержимое событий. Имя задачи bash, ее идентификатор PID — 1977, задача работает на CPU 000, задержка (формат описан ниже, временная метка в формате <сек>.<мксек>, имя отслеживаемой функции (sys_close и родительская функция system_call_fastpath). Временная метка показывает момент входа в функцию.

Формат трассировки задержек

При включенной опции latency-format или установке одного из трассировщиков задержки файл trace содержит дополнительную информацию, позволяющую увидеть причину задержки. Ниже приведен пример трассировки.

  # tracer: irqsoff
  #
  # irqsoff latency trace v1.1.5 on 3.8.0-test+
  # --------------------------------------------------------------------
  # latency: 259 us, #4/4, CPU#2 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
  #    -----------------
  #    | task: ps-6143 (uid:0 nice:0 policy:0 rt_prio:0)
  #    -----------------
  #  => started at: __lock_task_sighand
  #  => ended at:   _raw_spin_unlock_irqrestore
  #
  #
  #                  _------=> CPU#            
  #                 / _-----=> irqs-off        
  #                | / _----=> need-resched    
  #                || / _---=> hardirq/softirq 
  #                ||| / _--=> preempt-depth   
  #                |||| /     delay             
  #  cmd     pid   ||||| time  |   caller      
  #     \   /      |||||  \    |   /           
        ps-6143    2d...    0us!: trace_hardirqs_off <-__lock_task_sighand
        ps-6143    2d..1  259us+: trace_hardirqs_on <-_raw_spin_unlock_irqrestore
        ps-6143    2d..1  263us+: time_hardirqs_on <-_raw_spin_unlock_irqrestore
        ps-6143    2d..1  306us : <stack trace>
   => trace_hardirqs_on_caller
   => trace_hardirqs_on
   => _raw_spin_unlock_irqrestore
   => do_task_stat
   => proc_tgid_stat
   => proc_single_show
   => seq_read
   => vfs_read
   => sys_read
   => system_call_fastpath

Вывод показывает, что трассировщик irqsoff отслеживает время, на которое отключались прерывания. Указана версия трассировки (никогда не меняется) и версия ядра (3.8). Затем указана максимальная задержка в микросекундах (259), число показанных событий и общее их число (#4/4). VP, KP, SP и HP всегда имеют значение 0 (резерв на будущее). #P указывает число работающих процессоров CPU (#P:4).

В качестве задачи указывается процесс, который работал при возникновении задержки (ps pid: 6143).

Строки started at и ended at указывают функции, в которых прерывания были отключены и включены (соответственно), что и привело к задержке.

  • В функции __lock_task_sighand прерывания были отключены.

  • В функции _raw_spin_unlock_irqrestore прерывания были снова включены.

Далее следует заголовок, разъясняющий формат вывода, и результаты трассировки.

cmd

Имя процесса в трассировке.

pid

PID этого процесса.

CPU#

Номер CPU, на котором выполнялся процесс.

irqs-off

Символ d указывает запрет прерываний, в остальных случаях выводится точка (.). Если архитектура не поддерживает считывание переменной флагов irq, в этом поле всегда указывается символ X.

need-resched

  • N — установлены оба флага TIF_NEED_RESCHED и PREEMPT_NEED_RESCHED;
  • n — установлен только флаг TIF_NEED_RESCHED;
  • p — установлен только флаг PREEMPT_NEED_RESCHED;
  • . — иное.

hardirq/softirq

  • Z — прерывание NMI внутри hardirq;
  • z — NMI выполняется;
  • H — аппаратное irq внутри softirq;
  • h — аппаратное irq выполняется;
  • s — программное irq выполняется;
  • . — обычный контекст.

preempt-depth

Уровень preempt_disabled.

Описанное выше предназначено в основном для разработчиков ядра.

time:

При включенной опции latency-format вывод файла trace включает временные метки относительно начала трассировки, а при выключенной опции latency-format метки указываются в абсолютном времени.

delay

Это просто метки для упрощения зрительного восприятия, относящиеся к одному CPU и показывающие разницу между текущей и следующей трассировкой.

  • $ — больше 1 секунды;
  • @ — больше 100 миллисекунд;
  • * — больше 10 миллисекунд;
  • # — больше 1000 микросекунд;
  • ! — больше 100 микросекунд;
  • + — больше 10 микросекунд;
  • ‘ ‘ — не больше 10 микросекунд.

Остальная часть вывода такая же как для файла trace.

Отметим, что трассировщики задержки обычно завершаются трассировкой назад, чтобы было увидеть место задержки.

Опции трассировки — файл trace_options

Файл trace_options (или каталог options) служит для управления выводом трассировки или манипуляций с трассировщиками. Для просмотра доступного просто введите команду cat.

  cat trace_options
	print-parent
	nosym-offset
	nosym-addr
	noverbose
	noraw
	nohex
	nobin
	noblock
	trace_printk
	annotate
	nouserstacktrace
	nosym-userobj
	noprintk-msg-only
	context-info
	nolatency-format
	record-cmd
	norecord-tgid
	overwrite
	nodisable_on_free
	irq-info
	markers
	noevent-fork
	function-trace
	nofunction-fork
	nodisplay-graph
	nostacktrace
	nobranch

Для отключения нужной опции добавьте к ее имени префикс no и отправьте в файл trace_options4

  echo noprint-parent > trace_options

Для включения опции отправьте ее имя в файл trace_options

  echo sym-offset > trace_options

Список доступных опций приведен ниже.

print-parent

При трассировке функций задает вывод вызывающей (родительской) функции вместе с трассируемой.

print-parent

	   bash-4000  [01]  1477.606694: simple_strtoul <-kstrtoul

noprint-parent

	   bash-4000  [01]  1477.606694: simple_strtoul

sym-offset

Вывод не только имени функции, но и ее смещения. Например, вместо ktime_get будет ktime_get+0xb/0x20.

sym-offset

	   bash-4000  [01]  1477.606694: simple_strtoul+0x6/0xa0

sym-addr

Вывод адреса функции вместе с ее именем.

sym-addr

	   bash-4000  [01]  1477.606694: simple_strtoul <c0339346>

verbose

Задает подробный вывод в файле trace при включенной опции latency-format.

     bash  4000 1 0 00000000 00010a95 [58127d26] 1720.415ms  (+0.000ms): simple_strtoul (kstrtoul)

raw

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

hex

Похожа на raw, но числа выводятся в шестнадцатеричном формате.

bin

Вывод в необработанном двоичном формате.

block

При установленной опции считывание файла trace_pipe не будет блокироваться при опросе.

trace_printk

Может запрещать запись trace_printk() в буфер.

annotate

При заполненных буферах CPU может возникать путаница, когда в одном буфере имеется много свежих событий, а у другого событий немного и буфер будет содержать более старые события. При выводе трассировки сначала указываются более старые события и может показаться, что работает лишь один процессор. При включенном аннотировании будет указываться запуск нового буфера CPU.

			  <idle>-0     [001] dNs4 21169.031481: wake_up_idle_cpu <-add_timer_on
			  <idle>-0     [001] dNs4 21169.031482: _raw_spin_unlock_irqrestore <-add_timer_on
			  <idle>-0     [001] .Ns4 21169.031484: sub_preempt_count <-_raw_spin_unlock_irqrestore
		##### CPU 2 buffer started ####
			  <idle>-0     [002] .N.1 21169.031484: rcu_idle_exit <-cpu_idle
			  <idle>-0     [001] .Ns3 21169.031484: _raw_spin_unlock <-clocksource_watchdog
			  <idle>-0     [001] .Ns3 21169.031485: sub_preempt_count <-_raw_spin_unlock

userstacktrace

Эта опция меняет трассировку и ведет к записи трассировки стека (stacktrace) текущего потока пользовательского пространства после каждого трассируемого события.

sym-userobj

При включенной опции userstacktrace определяется, к какому объекту относится адрес и выводится относительный адрес. Это особенно полезно при включенном ASLR, поскольку иначе не будет возможности преобразовать адрес в объект/файл/строку после того, как приложение прекратит работу. Поиск выполняется при чтении trace или trace_pipe.

		  a.out-1623  [000] 40874.465068: /root/a.out[+0x480] <-/root/a.out[+0
		  x494] <- /root/a.out[+0x4a8] <- /lib/libc-2.7.so[+0x1e1a6]

printk-msg-only

При установке этой опции trace_printk() будет показывать только формат, а не параметры (если использовался вызов trace_bprintk() или trace_bputs() для сохранения trace_printk()).

context-info

Задает вывод только событий без команд, PID, временных меток, CPU и других данных.

latency-format

Эта опция меняет вывод трассировки и при включении обеспечивает дополнительную информацию о задержке, как описано в разделе Формат трассировки задержек.

record-cmd

При включении любого события или трассировщика в точке трассировки sched_switch включается ловушка для заполнения кэша сопоставлений pid и команд. Однако это может приводить к издержкам и если вам достаточно pid без имен задач, отключение этой опции может снизить влияние на трассировку (см. saved_cmdlines).

record-tgid

При включении любого события или трассировщика в точке трассировки sched_switch включается ловушка для заполнения кэша сопоставлений pid и TGID5 (см. saved_tgids).

overwrite

Управляет поведением при заполнении буфера трассировки. Значение 1 (принято по умолчанию) ведет к перезаписи самых старых событий, 0 — к перезаписи самых новых (см. per_cpu/cpu0/stats, где указаны переполнения и отбрасывания).

disable_on_free

При закрытии free_buffer трассировка будет прекращаться (устанавливается tracing_on = 0).

irq-info

Показывает прерывание, счетчик вытеснения и необходимость перепланировки данных. При отключенной опции трассировка будет иметь вид

# tracer: function
#
# entries-in-buffer/entries-written: 144405/9452052   #P:4
#
#           TASK-PID   CPU#      TIMESTAMP  FUNCTION
#              | |       |          |         |
	  <idle>-0     [002]  23636.756054: ttwu_do_activate.constprop.89 <-try_to_wake_up
	  <idle>-0     [002]  23636.756054: activate_task <-ttwu_do_activate.constprop.89
	  <idle>-0     [002]  23636.756055: enqueue_task <-activate_task

markers

Установка опции открывает файл trace_marker для записи (пользователю root). При отключенной опции запись в trace_marker будет приводить к ошибке EINVAL.

event-fork

При установке опции для задач, PID которых указаны в set_event_pid, в этот файл будут добавляться при ветвлении PID дочерних процессов. При завершении задачи с PID, указанным в set_event_pid, значение PID будет удаляться из файла.

function-trace

При включенной опции трассировщики задержек будут включать трассировку функций (принято по умолчанию). Если опция не установлена при трассировке задержки функции отслеживаться не будут для снижения издержек.

function-fork

При установке опции для задач, PID которых указаны в set_ftrace_pid, в этот файл будут добавляться при ветвлении PID дочерних процессов. При завершении задачи с PID, указанным в set_ftrace_pid exit, значение PID будет удаляться из файла.

display-graph

При включенной опции трассировщик задержек (irqsoff, wakeup и т. п.) будет применять трассировку function_graph вместо function.

stacktrace

При включенной опции записывается трассировка стека после записи любого события.

branch

Разрешает трассировку ветвления, включая трассировщик branch вместе с текущим трассировщиком. Включение этой опции с трассировщиком nop эквивалентно простому включению трассировщика branch.

Примечание. У некоторых трассировщиков имеются свои опции, которые выводятся в файле только при их активизации. Однако они всегда присутствуют в каталоге options.

Ниже рассматриваются опции отдельных трассировщиков.

Опции трассировщика function

func_stack_trace

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

Опции трассировщика function_graph

Поскольку трассировщик function_graph отличается выводом, у него имеются свои опции для контроля вывода.

funcgraph-overrun

При установке опции «переполнение» стека function_graph отображается после каждой отслеживаемой функции. Переполнение возникает, когда грубина стека вызовов превышает значение, зарезервированное для каждой задачи. Каждая задача имеет фиксированный массив функций для отслеживания в графе вызовов. Если глубина вызовов превышает предел, функция не отслеживается. Переполнение — это число функций, пропущенных в результате превышения массива.

funcgraph-cpu

При установке опции отображается номер CPU, где выполнялась трассировка.

funcgraph-overhead

При установленной опции отображается маркер задержки, если функция заняла время, превышающее некое значение.

funcgraph-proc

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

funcgraph-duration

В конце каждой функции (возврат) выводится продолжительность ее работы в микросекундах.

funcgraph-abstime

При установке опции в каждой строке выводится временная метка.

funcgraph-irqs

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

funcgraph-tail

При установленной опции событие возврата будет включать представляемую им функцию. По умолчанию это отключено и при возврате из функции отображается лишь фигурная скобка }.

sleep-time

Служит для учета запланированного времени задачи при работе трассировщика function_graph. При включенной опции запланированное время будет учитываться как часть вызова функции.

graph-time

При запуске профилировщика функций с трассировщиком function_graph служит для включения времени вызова вложенных функций. Если опция не задана, указываемое для функции время будет включать только время выполнения самой функции без учета вызываемых ею функций.

Опции трассировщика blk

  blk_classic

Задает минимальный
вывод
.

Трассировщик irqsoff

При отключенных прерываниях CPU не может реагировать на другие внешние события, кроме NMI и SMI. В результате замедляется реакция системы на события.

Трассировщик irqsoff отслеживает периоды запрета прерываний. При достижении нового значения максимальной задержки трассировщик сохраняет трассировку к точке задержки, чтобы при достижении нового максимума прежнее значения отбрасывалось, а новое записывалось.

Для сброса максимума записывается значение 0 в файл tracing_max_latency. Ниже приведен пример.

  # echo 0 > options/function-trace
  # echo irqsoff > current_tracer
  # echo 1 > tracing_on
  # echo 0 > tracing_max_latency
  # ls -ltr
  [...]
  # echo 0 > tracing_on
  # cat trace
  # tracer: irqsoff
  #
  # irqsoff latency trace v1.1.5 on 3.8.0-test+
  # --------------------------------------------------------------------
  # latency: 16 us, #4/4, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
  #    -----------------
  #    | task: swapper/0-0 (uid:0 nice:0 policy:0 rt_prio:0)
  #    -----------------
  #  => started at: run_timer_softirq
  #  => ended at:   run_timer_softirq
  #
  #
  #                  _------=> CPU#            
  #                 / _-----=> irqs-off        
  #                | / _----=> need-resched    
  #                || / _---=> hardirq/softirq 
  #                ||| / _--=> preempt-depth   
  #                |||| /     delay             
  #  cmd     pid   ||||| time  |   caller      
  #     \   /      |||||  \    |   /           
    <idle>-0       0d.s2    0us+: _raw_spin_lock_irq <-run_timer_softirq
    <idle>-0       0dNs3   17us : _raw_spin_unlock_irq <-run_timer_softirq
    <idle>-0       0dNs3   17us+: trace_hardirqs_on <-run_timer_softirq
    <idle>-0       0dNs3   25us : <stack trace>
   => _raw_spin_unlock_irq
   => run_timer_softirq
   => __do_softirq
   => call_softirq
   => do_softirq
   => irq_exit
   => smp_apic_timer_interrupt
   => apic_timer_interrupt
   => rcu_idle_exit
   => cpu_idle
   => rest_init
   => start_kernel
   => x86_64_start_reservations
   => x86_64_start_kernel

Вывод показывает задержку 16 мксек (очень хорошо). Прерывания отключены функцией _raw_spin_lock_irq в run_timer_softirq. Разница между задержкой в 16 мксек и показанной временной меткой 25us обусловлена инкрементированием часов между моментами записи максимальной задержки и функции, вызвавшей эту задержку.

Отметим, что в приведенном выше примере опция function-trace не была установлена и при ее установке вывод будет более подробным, как показано ниже.

 with echo 1 > options/function-trace
  # tracer: irqsoff
  #
  # irqsoff latency trace v1.1.5 on 3.8.0-test+
  # --------------------------------------------------------------------
  # latency: 71 us, #168/168, CPU#3 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
  #    -----------------
  #    | task: bash-2042 (uid:0 nice:0 policy:0 rt_prio:0)
  #    -----------------
  #  => started at: ata_scsi_queuecmd
  #  => ended at:   ata_scsi_queuecmd
  #
  #
  #                  _------=> CPU#            
  #                 / _-----=> irqs-off        
  #                | / _----=> need-resched    
  #                || / _---=> hardirq/softirq 
  #                ||| / _--=> preempt-depth   
  #                |||| /     delay             
  #  cmd     pid   ||||| time  |   caller      
  #     \   /      |||||  \    |   /           
      bash-2042    3d...    0us : _raw_spin_lock_irqsave <-ata_scsi_queuecmd
      bash-2042    3d...    0us : add_preempt_count <-_raw_spin_lock_irqsave
      bash-2042    3d..1    1us : ata_scsi_find_dev <-ata_scsi_queuecmd
      bash-2042    3d..1    1us : __ata_scsi_find_dev <-ata_scsi_find_dev
      bash-2042    3d..1    2us : ata_find_dev.part.14 <-__ata_scsi_find_dev
      bash-2042    3d..1    2us : ata_qc_new_init <-__ata_scsi_queuecmd
      bash-2042    3d..1    3us : ata_sg_init <-__ata_scsi_queuecmd
      bash-2042    3d..1    4us : ata_scsi_rw_xlat <-__ata_scsi_queuecmd
      bash-2042    3d..1    4us : ata_build_rw_tf <-ata_scsi_rw_xlat
  [...]
      bash-2042    3d..1   67us : delay_tsc <-__delay
      bash-2042    3d..1   67us : add_preempt_count <-delay_tsc
      bash-2042    3d..2   67us : sub_preempt_count <-delay_tsc
      bash-2042    3d..1   67us : add_preempt_count <-delay_tsc
      bash-2042    3d..2   68us : sub_preempt_count <-delay_tsc
      bash-2042    3d..1   68us+: ata_bmdma_start <-ata_bmdma_qc_issue
      bash-2042    3d..1   71us : _raw_spin_unlock_irqrestore <-ata_scsi_queuecmd
      bash-2042    3d..1   71us : _raw_spin_unlock_irqrestore <-ata_scsi_queuecmd
      bash-2042    3d..1   72us+: trace_hardirqs_on <-ata_scsi_queuecmd
      bash-2042    3d..1  120us : <stack trace>
   => _raw_spin_unlock_irqrestore
   => ata_scsi_queuecmd
   => scsi_dispatch_cmd
   => scsi_request_fn
   => __blk_run_queue_uncond
   => __blk_run_queue
   => blk_queue_bio
   => generic_make_request
   => submit_bio
   => submit_bh
   => __ext3_get_inode_loc
   => ext3_iget
   => ext3_lookup
   => lookup_real
   => __lookup_hash
   => walk_component
   => lookup_last
   => path_lookupat
   => filename_lookup
   => user_path_at_empty
   => user_path_at
   => vfs_fstatat
   => vfs_stat
   => sys_newstat
   => system_call_fastpath

Здесь показана задержка в 71 мксек, но видны функции, которые вызвались в это время. Отметим, что включение трассировки функций увеличило издержки, которые могли привести к росту задержки. Тем не менее, эта трассировка содержит много полезной для отладки информации.

Трассировщик preemptoff

При отключенном вытеснении (preemption) прерывания будут работать, но задачи не могут вытеснять друг друга и в результате задаче с высоким приоритетом может потребоваться ожидать возможности вытеснения менее приоритетной задачи.

Трассировщик preemptoff отслеживает места, где вытеснение запрещено. Подобно трассировщику irqsoff, он записывает максимальную задержку, для которой вытеснение было отключено. Управление трассировщиком preemptoff похоже на управление irqsoff.

  # echo 0 > options/function-trace
  # echo preemptoff > current_tracer
  # echo 1 > tracing_on
  # echo 0 > tracing_max_latency
  # ls -ltr
  [...]
  # echo 0 > tracing_on
  # cat trace
  # tracer: preemptoff
  #
  # preemptoff latency trace v1.1.5 on 3.8.0-test+
  # --------------------------------------------------------------------
  # latency: 46 us, #4/4, CPU#1 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
  #    -----------------
  #    | task: sshd-1991 (uid:0 nice:0 policy:0 rt_prio:0)
  #    -----------------
  #  => started at: do_IRQ
  #  => ended at:   do_IRQ
  #
  #
  #                  _------=> CPU#            
  #                 / _-----=> irqs-off        
  #                | / _----=> need-resched    
  #                || / _---=> hardirq/softirq 
  #                ||| / _--=> preempt-depth   
  #                |||| /     delay             
  #  cmd     pid   ||||| time  |   caller      
  #     \   /      |||||  \    |   /           
      sshd-1991    1d.h.    0us+: irq_enter <-do_IRQ
      sshd-1991    1d..1   46us : irq_exit <-do_IRQ
      sshd-1991    1d..1   47us+: trace_preempt_on <-do_IRQ
      sshd-1991    1d..1   52us : <stack trace>
   => sub_preempt_count
   => irq_exit
   => do_IRQ
   => ret_from_intr

Здесь видны некоторые отличия. Вытеснение было отключено во время прерывания (символ h) и восстановлено по завершении. Однако можно видеть, что прерывания были отключены при входе в раздел preempt off и на выходе из него (символ d). Неизвестно, были ли прерывания включены в это время или вскоре после него.

  # tracer: preemptoff
  #
  # preemptoff latency trace v1.1.5 on 3.8.0-test+
  # --------------------------------------------------------------------
  # latency: 83 us, #241/241, CPU#1 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
  #    -----------------
  #    | task: bash-1994 (uid:0 nice:0 policy:0 rt_prio:0)
  #    -----------------
  #  => started at: wake_up_new_task
  #  => ended at:   task_rq_unlock
  #
  #
  #                  _------=> CPU#            
  #                 / _-----=> irqs-off        
  #                | / _----=> need-resched    
  #                || / _---=> hardirq/softirq 
  #                ||| / _--=> preempt-depth   
  #                |||| /     delay             
  #  cmd     pid   ||||| time  |   caller      
  #     \   /      |||||  \    |   /           
      bash-1994    1d..1    0us : _raw_spin_lock_irqsave <-wake_up_new_task
      bash-1994    1d..1    0us : select_task_rq_fair <-select_task_rq
      bash-1994    1d..1    1us : __rcu_read_lock <-select_task_rq_fair
      bash-1994    1d..1    1us : source_load <-select_task_rq_fair
      bash-1994    1d..1    1us : source_load <-select_task_rq_fair
  [...]
      bash-1994    1d..1   12us : irq_enter <-smp_apic_timer_interrupt
      bash-1994    1d..1   12us : rcu_irq_enter <-irq_enter
      bash-1994    1d..1   13us : add_preempt_count <-irq_enter
      bash-1994    1d.h1   13us : exit_idle <-smp_apic_timer_interrupt
      bash-1994    1d.h1   13us : hrtimer_interrupt <-smp_apic_timer_interrupt
      bash-1994    1d.h1   13us : _raw_spin_lock <-hrtimer_interrupt
      bash-1994    1d.h1   14us : add_preempt_count <-_raw_spin_lock
      bash-1994    1d.h2   14us : ktime_get_update_offsets <-hrtimer_interrupt
  [...]
      bash-1994    1d.h1   35us : lapic_next_event <-clockevents_program_event
      bash-1994    1d.h1   35us : irq_exit <-smp_apic_timer_interrupt
      bash-1994    1d.h1   36us : sub_preempt_count <-irq_exit
      bash-1994    1d..2   36us : do_softirq <-irq_exit
      bash-1994    1d..2   36us : __do_softirq <-call_softirq
      bash-1994    1d..2   36us : __local_bh_disable <-__do_softirq
      bash-1994    1d.s2   37us : add_preempt_count <-_raw_spin_lock_irq
      bash-1994    1d.s3   38us : _raw_spin_unlock <-run_timer_softirq
      bash-1994    1d.s3   39us : sub_preempt_count <-_raw_spin_unlock
      bash-1994    1d.s2   39us : call_timer_fn <-run_timer_softirq
  [...]
      bash-1994    1dNs2   81us : cpu_needs_another_gp <-rcu_process_callbacks
      bash-1994    1dNs2   82us : __local_bh_enable <-__do_softirq
      bash-1994    1dNs2   82us : sub_preempt_count <-__local_bh_enable
      bash-1994    1dN.2   82us : idle_cpu <-irq_exit
      bash-1994    1dN.2   83us : rcu_irq_exit <-irq_exit
      bash-1994    1dN.2   83us : sub_preempt_count <-irq_exit
      bash-1994    1.N.1   84us : _raw_spin_unlock_irqrestore <-task_rq_unlock
      bash-1994    1.N.1   84us+: trace_preempt_on <-task_rq_unlock
      bash-1994    1.N.1  104us : <stack trace>
   => sub_preempt_count
   => _raw_spin_unlock_irqrestore
   => task_rq_unlock
   => wake_up_new_task
   => do_fork
   => sys_clone
   => stub_clone

Выше приведен пример трассировки preemptoff с включенной опцией function-trace. Здесь видно, что прерывания были отключены не все время. Код irq_enter указывает вход в прерывание h. Перед этим отслеживаемые функции показывают, что они не находятся в прерывании, но из самих функций видно, что это не так.

Трассировщик preemptirqsoff

Полезно знать места, где прерывания или вытеснение были отключены на самое продолжительное время. Однако иногда нужно знать, когда прерывания и/или вытеснение были отключены. Рассмотрим пример кода.

    local_irq_disable();
    call_function_with_irqs_off();
    preempt_disable();
    call_function_with_irqs_and_preemption_off();
    local_irq_enable();
    call_function_with_preemption_off();
    preempt_enable();

Трассировщик irqsoff записывает общую продолжительность вызовов call_function_with_irqs_off() и call_function_with_irqs_and_preemption_off(), preemptoff — общую продолжительность call_function_with_irqs_and_preemption_off() и call_function_with_preemption_off(). Но ни один из них не записывает время, в течение которого прерывания и/или вытеснение были отключены. Это общее время, которое мы не можем планировать. Для записи этого времени служит трассировщик preemptirqsoff.

Работа с этим трассировщиком похожа на действия с irqsoff и preemptoff.

  # echo 0 > options/function-trace
  # echo preemptirqsoff > current_tracer
  # echo 1 > tracing_on
  # echo 0 > tracing_max_latency
  # ls -ltr
  [...]
  # echo 0 > tracing_on
  # cat trace
  # tracer: preemptirqsoff
  #
  # preemptirqsoff latency trace v1.1.5 on 3.8.0-test+
  # --------------------------------------------------------------------
  # latency: 100 us, #4/4, CPU#3 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
  #    -----------------
  #    | task: ls-2230 (uid:0 nice:0 policy:0 rt_prio:0)
  #    -----------------
  #  => started at: ata_scsi_queuecmd
  #  => ended at:   ata_scsi_queuecmd
  #
  #
  #                  _------=> CPU#            
  #                 / _-----=> irqs-off        
  #                | / _----=> need-resched    
  #                || / _---=> hardirq/softirq 
  #                ||| / _--=> preempt-depth   
  #                |||| /     delay             
  #  cmd     pid   ||||| time  |   caller      
  #     \   /      |||||  \    |   /           
        ls-2230    3d...    0us+: _raw_spin_lock_irqsave <-ata_scsi_queuecmd
        ls-2230    3...1  100us : _raw_spin_unlock_irqrestore <-ata_scsi_queuecmd
        ls-2230    3...1  101us+: trace_preempt_on <-ata_scsi_queuecmd
        ls-2230    3...1  111us : <stack trace>
   => sub_preempt_count
   => _raw_spin_unlock_irqrestore
   => ata_scsi_queuecmd
   => scsi_dispatch_cmd
   => scsi_request_fn
   => __blk_run_queue_uncond
   => __blk_run_queue
   => blk_queue_bio
   => generic_make_request
   => submit_bio
   => submit_bh
   => ext3_bread
   => ext3_dir_bread
   => htree_dirblock_to_tree
   => ext3_htree_fill_tree
   => ext3_readdir
   => vfs_readdir
   => sys_getdents
   => system_call_fastpath

Вызов trace_hardirqs_off_thunk выполняется из сборки кода x86 когда прерывания запрещены в этой сборке. Без трассировки функций мы не узнаем, были ли прерывания запрещены в пределах точек вытеснения. Видно, что это начинается с включения вытеснения. Ниже показана трассировка с включенной опцией function-trace.

  # tracer: preemptirqsoff
  #
  # preemptirqsoff latency trace v1.1.5 on 3.8.0-test+
  # --------------------------------------------------------------------
  # latency: 161 us, #339/339, CPU#3 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
  #    -----------------
  #    | task: ls-2269 (uid:0 nice:0 policy:0 rt_prio:0)
  #    -----------------
  #  => started at: schedule
  #  => ended at:   mutex_unlock
  #
  #
  #                  _------=> CPU#            
  #                 / _-----=> irqs-off        
  #                | / _----=> need-resched    
  #                || / _---=> hardirq/softirq 
  #                ||| / _--=> preempt-depth   
  #                |||| /     delay             
  #  cmd     pid   ||||| time  |   caller      
  #     \   /      |||||  \    |   /           
  kworker/-59      3...1    0us : __schedule <-schedule
  kworker/-59      3d..1    0us : rcu_preempt_qs <-rcu_note_context_switch
  kworker/-59      3d..1    1us : add_preempt_count <-_raw_spin_lock_irq
  kworker/-59      3d..2    1us : deactivate_task <-__schedule
  kworker/-59      3d..2    1us : dequeue_task <-deactivate_task
  kworker/-59      3d..2    2us : update_rq_clock <-dequeue_task
  kworker/-59      3d..2    2us : dequeue_task_fair <-dequeue_task
  kworker/-59      3d..2    2us : update_curr <-dequeue_task_fair
  kworker/-59      3d..2    2us : update_min_vruntime <-update_curr
  kworker/-59      3d..2    3us : cpuacct_charge <-update_curr
  kworker/-59      3d..2    3us : __rcu_read_lock <-cpuacct_charge
  kworker/-59      3d..2    3us : __rcu_read_unlock <-cpuacct_charge
  kworker/-59      3d..2    3us : update_cfs_rq_blocked_load <-dequeue_task_fair
  kworker/-59      3d..2    4us : clear_buddies <-dequeue_task_fair
  kworker/-59      3d..2    4us : account_entity_dequeue <-dequeue_task_fair
  kworker/-59      3d..2    4us : update_min_vruntime <-dequeue_task_fair
  kworker/-59      3d..2    4us : update_cfs_shares <-dequeue_task_fair
  kworker/-59      3d..2    5us : hrtick_update <-dequeue_task_fair
  kworker/-59      3d..2    5us : wq_worker_sleeping <-__schedule
  kworker/-59      3d..2    5us : kthread_data <-wq_worker_sleeping
  kworker/-59      3d..2    5us : put_prev_task_fair <-__schedule
  kworker/-59      3d..2    6us : pick_next_task_fair <-pick_next_task
  kworker/-59      3d..2    6us : clear_buddies <-pick_next_task_fair
  kworker/-59      3d..2    6us : set_next_entity <-pick_next_task_fair
  kworker/-59      3d..2    6us : update_stats_wait_end <-set_next_entity
        ls-2269    3d..2    7us : finish_task_switch <-__schedule
        ls-2269    3d..2    7us : _raw_spin_unlock_irq <-finish_task_switch
        ls-2269    3d..2    8us : do_IRQ <-ret_from_intr
        ls-2269    3d..2    8us : irq_enter <-do_IRQ
        ls-2269    3d..2    8us : rcu_irq_enter <-irq_enter
        ls-2269    3d..2    9us : add_preempt_count <-irq_enter
        ls-2269    3d.h2    9us : exit_idle <-do_IRQ
  [...]
        ls-2269    3d.h3   20us : sub_preempt_count <-_raw_spin_unlock
        ls-2269    3d.h2   20us : irq_exit <-do_IRQ
        ls-2269    3d.h2   21us : sub_preempt_count <-irq_exit
        ls-2269    3d..3   21us : do_softirq <-irq_exit
        ls-2269    3d..3   21us : __do_softirq <-call_softirq
        ls-2269    3d..3   21us+: __local_bh_disable <-__do_softirq
        ls-2269    3d.s4   29us : sub_preempt_count <-_local_bh_enable_ip
        ls-2269    3d.s5   29us : sub_preempt_count <-_local_bh_enable_ip
        ls-2269    3d.s5   31us : do_IRQ <-ret_from_intr
        ls-2269    3d.s5   31us : irq_enter <-do_IRQ
        ls-2269    3d.s5   31us : rcu_irq_enter <-irq_enter
  [...]
        ls-2269    3d.s5   31us : rcu_irq_enter <-irq_enter
        ls-2269    3d.s5   32us : add_preempt_count <-irq_enter
        ls-2269    3d.H5   32us : exit_idle <-do_IRQ
        ls-2269    3d.H5   32us : handle_irq <-do_IRQ
        ls-2269    3d.H5   32us : irq_to_desc <-handle_irq
        ls-2269    3d.H5   33us : handle_fasteoi_irq <-handle_irq
  [...]
        ls-2269    3d.s5  158us : _raw_spin_unlock_irqrestore <-rtl8139_poll
        ls-2269    3d.s3  158us : net_rps_action_and_irq_enable.isra.65 <-net_rx_action
        ls-2269    3d.s3  159us : __local_bh_enable <-__do_softirq
        ls-2269    3d.s3  159us : sub_preempt_count <-__local_bh_enable
        ls-2269    3d..3  159us : idle_cpu <-irq_exit
        ls-2269    3d..3  159us : rcu_irq_exit <-irq_exit
        ls-2269    3d..3  160us : sub_preempt_count <-irq_exit
        ls-2269    3d...  161us : __mutex_unlock_slowpath <-mutex_unlock
        ls-2269    3d...  162us+: trace_hardirqs_on <-mutex_unlock
        ls-2269    3d...  186us : <stack trace>
   => __mutex_unlock_slowpath
   => mutex_unlock
   => process_output
   => n_tty_write
   => tty_write
   => vfs_write
   => sys_write
   => system_call_fastpath

Эта интересная трассировка, которая начинается с того, что процесс kworker работает и запланирован, но ls берет управление на себя. Как только ls освобождает rq и разрешает прерывания (но не вытеснение), сразу срабатывает прерывание. По завершении прерывания запускаются softirq, но во время работы softirq происходит другое прерывание, завершение которого внутри softirq указывается символом H.

Трассировщик wakeup

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

Ниже приведена трассировка без отслеживания функций.

  # echo 0 > options/function-trace
  # echo wakeup > current_tracer
  # echo 1 > tracing_on
  # echo 0 > tracing_max_latency
  # chrt -f 5 sleep 1
  # echo 0 > tracing_on
  # cat trace
  # tracer: wakeup
  #
  # wakeup latency trace v1.1.5 on 3.8.0-test+
  # --------------------------------------------------------------------
  # latency: 15 us, #4/4, CPU#3 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
  #    -----------------
  #    | task: kworker/3:1H-312 (uid:0 nice:-20 policy:0 rt_prio:0)
  #    -----------------
  #
  #                  _------=> CPU#            
  #                 / _-----=> irqs-off        
  #                | / _----=> need-resched    
  #                || / _---=> hardirq/softirq 
  #                ||| / _--=> preempt-depth   
  #                |||| /     delay             
  #  cmd     pid   ||||| time  |   caller      
  #     \   /      |||||  \    |   /           
    <idle>-0       3dNs7    0us :      0:120:R   + [003]   312:100:R kworker/3:1H
    <idle>-0       3dNs7    1us+: ttwu_do_activate.constprop.87 <-try_to_wake_up
    <idle>-0       3d..3   15us : __schedule <-schedule
    <idle>-0       3d..3   15us :      0:120:R ==> [003]   312:100:R kworker/3:1H

Трассировщик отслеживает лишь задачи с наиболее высоким приоритетом в системе, не трассируя обычные ситуации. Можно видеть, что для задачи kworker с приоритетом nice = of -20 (не очень высокий) прошло лишь 15 мксек между пробуждением и началом работы.

Задачи, не работающие в режиме реального времени (RT), не так интересны, по сравнению с задачами RT.

Трассировщик wakeup_rt

В среде RT очень важно знать, какое время проходит между пробуждением задачи с наивысшим приоритетом и началом ее выполнения. Это время называют также задержкой планирования (schedule latency). Подчеркнем, что речь здесь идет только о задачах RT. Важно также понимать задержку планирования для задач не-RT, но для них лучше средняя задержка планирования. Для таких измерений лучше подходят такие инструменты, как LatencyTop.

Для сред RT интересна задержка в худшей ситуации. Это наибольшая, а не средняя задержка. У нас может быть очень быстрый планировщик, который будет редко приводить к значительным задержкам, но он может быть недостаточно хорош для задач RT. Трассировщик wakeup_rt был разработан для определения худшего варианта пробуждения задач RT. Другие (не-RT) задачи не отслеживаются, поскольку трассировщик записывает один наихудший случай, а отслеживание задач не-RT, дающее непредсказуемый результат, будет переписывать наихудшую задержку для задач RT (это легко увидеть при запуске трассировщика wakeup).

Поскольку этот трассировщик работает только с задачами RT, воспользуемся для него вместо привычной команды ls командой sleep 1 в chrt, где меняется приоритет задачи.

  # echo 0 > options/function-trace
  # echo wakeup_rt > current_tracer
  # echo 1 > tracing_on
  # echo 0 > tracing_max_latency
  # chrt -f 5 sleep 1
  # echo 0 > tracing_on
  # cat trace
  # tracer: wakeup
  #
  # tracer: wakeup_rt
  #
  # wakeup_rt latency trace v1.1.5 on 3.8.0-test+
  # --------------------------------------------------------------------
  # latency: 5 us, #4/4, CPU#3 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
  #    -----------------
  #    | task: sleep-2389 (uid:0 nice:0 policy:1 rt_prio:5)
  #    -----------------
  #
  #                  _------=> CPU#            
  #                 / _-----=> irqs-off        
  #                | / _----=> need-resched    
  #                || / _---=> hardirq/softirq 
  #                ||| / _--=> preempt-depth   
  #                |||| /     delay             
  #  cmd     pid   ||||| time  |   caller      
  #     \   /      |||||  \    |   /           
    <idle>-0       3d.h4    0us :      0:120:R   + [003]  2389: 94:R sleep
    <idle>-0       3d.h4    1us+: ttwu_do_activate.constprop.87 <-try_to_wake_up
    <idle>-0       3d..3    5us : __schedule <-schedule
    <idle>-0       3d..3    5us :      0:120:R ==> [003]  2389: 94:R sleep

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

Отметим, что записываемая задача «спит» (sleep) с PID = 2389 и имеет rt_prio = 5. Этот приоритет относится к пользовательскому пространству, а не к ядру. Для SCHED_FIFO используется правило 1, для SCHED_RR — 2.

Отметим, что данные трассировки показывают внутренний приоритет (99 — rt_prio).

  <idle>-0       3d..3    5us :      0:120:R ==> [003]  2389: 94:R sleep

Запись 0:120:R означает бездействие с приоритетом nice = 0 (120 — 120), в рабочем состоянии (R). Спящая задача запланирована с 2389: 94:R. Т. е. приоритет является приоритетом ядра rt_prio (99 — 5 = 94) и задача также выполняется.

Повторим это с chrt -r 5 и установленной опцией function-trace.

  echo 1 > options/function-trace

  # tracer: wakeup_rt
  #
  # wakeup_rt latency trace v1.1.5 on 3.8.0-test+
  # --------------------------------------------------------------------
  # latency: 29 us, #85/85, CPU#3 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
  #    -----------------
  #    | task: sleep-2448 (uid:0 nice:0 policy:1 rt_prio:5)
  #    -----------------
  #
  #                  _------=> CPU#            
  #                 / _-----=> irqs-off        
  #                | / _----=> need-resched    
  #                || / _---=> hardirq/softirq 
  #                ||| / _--=> preempt-depth   
  #                |||| /     delay             
  #  cmd     pid   ||||| time  |   caller      
  #     \   /      |||||  \    |   /           
    <idle>-0       3d.h4    1us+:      0:120:R   + [003]  2448: 94:R sleep
    <idle>-0       3d.h4    2us : ttwu_do_activate.constprop.87 <-try_to_wake_up
    <idle>-0       3d.h3    3us : check_preempt_curr <-ttwu_do_wakeup
    <idle>-0       3d.h3    3us : resched_curr <-check_preempt_curr
    <idle>-0       3dNh3    4us : task_woken_rt <-ttwu_do_wakeup
    <idle>-0       3dNh3    4us : _raw_spin_unlock <-try_to_wake_up
    <idle>-0       3dNh3    4us : sub_preempt_count <-_raw_spin_unlock
    <idle>-0       3dNh2    5us : ttwu_stat <-try_to_wake_up
    <idle>-0       3dNh2    5us : _raw_spin_unlock_irqrestore <-try_to_wake_up
    <idle>-0       3dNh2    6us : sub_preempt_count <-_raw_spin_unlock_irqrestore
    <idle>-0       3dNh1    6us : _raw_spin_lock <-__run_hrtimer
    <idle>-0       3dNh1    6us : add_preempt_count <-_raw_spin_lock
    <idle>-0       3dNh2    7us : _raw_spin_unlock <-hrtimer_interrupt
    <idle>-0       3dNh2    7us : sub_preempt_count <-_raw_spin_unlock
    <idle>-0       3dNh1    7us : tick_program_event <-hrtimer_interrupt
    <idle>-0       3dNh1    7us : clockevents_program_event <-tick_program_event
    <idle>-0       3dNh1    8us : ktime_get <-clockevents_program_event
    <idle>-0       3dNh1    8us : lapic_next_event <-clockevents_program_event
    <idle>-0       3dNh1    8us : irq_exit <-smp_apic_timer_interrupt
    <idle>-0       3dNh1    9us : sub_preempt_count <-irq_exit
    <idle>-0       3dN.2    9us : idle_cpu <-irq_exit
    <idle>-0       3dN.2    9us : rcu_irq_exit <-irq_exit
    <idle>-0       3dN.2   10us : rcu_eqs_enter_common.isra.45 <-rcu_irq_exit
    <idle>-0       3dN.2   10us : sub_preempt_count <-irq_exit
    <idle>-0       3.N.1   11us : rcu_idle_exit <-cpu_idle
    <idle>-0       3dN.1   11us : rcu_eqs_exit_common.isra.43 <-rcu_idle_exit
    <idle>-0       3.N.1   11us : tick_nohz_idle_exit <-cpu_idle
    <idle>-0       3dN.1   12us : menu_hrtimer_cancel <-tick_nohz_idle_exit
    <idle>-0       3dN.1   12us : ktime_get <-tick_nohz_idle_exit
    <idle>-0       3dN.1   12us : tick_do_update_jiffies64 <-tick_nohz_idle_exit
    <idle>-0       3dN.1   13us : cpu_load_update_nohz <-tick_nohz_idle_exit
    <idle>-0       3dN.1   13us : _raw_spin_lock <-cpu_load_update_nohz
    <idle>-0       3dN.1   13us : add_preempt_count <-_raw_spin_lock
    <idle>-0       3dN.2   13us : __cpu_load_update <-cpu_load_update_nohz
    <idle>-0       3dN.2   14us : sched_avg_update <-__cpu_load_update
    <idle>-0       3dN.2   14us : _raw_spin_unlock <-cpu_load_update_nohz
    <idle>-0       3dN.2   14us : sub_preempt_count <-_raw_spin_unlock
    <idle>-0       3dN.1   15us : calc_load_nohz_stop <-tick_nohz_idle_exit
    <idle>-0       3dN.1   15us : touch_softlockup_watchdog <-tick_nohz_idle_exit
    <idle>-0       3dN.1   15us : hrtimer_cancel <-tick_nohz_idle_exit
    <idle>-0       3dN.1   15us : hrtimer_try_to_cancel <-hrtimer_cancel
    <idle>-0       3dN.1   16us : lock_hrtimer_base.isra.18 <-hrtimer_try_to_cancel
    <idle>-0       3dN.1   16us : _raw_spin_lock_irqsave <-lock_hrtimer_base.isra.18
    <idle>-0       3dN.1   16us : add_preempt_count <-_raw_spin_lock_irqsave
    <idle>-0       3dN.2   17us : __remove_hrtimer <-remove_hrtimer.part.16
    <idle>-0       3dN.2   17us : hrtimer_force_reprogram <-__remove_hrtimer
    <idle>-0       3dN.2   17us : tick_program_event <-hrtimer_force_reprogram
    <idle>-0       3dN.2   18us : clockevents_program_event <-tick_program_event
    <idle>-0       3dN.2   18us : ktime_get <-clockevents_program_event
    <idle>-0       3dN.2   18us : lapic_next_event <-clockevents_program_event
    <idle>-0       3dN.2   19us : _raw_spin_unlock_irqrestore <-hrtimer_try_to_cancel
    <idle>-0       3dN.2   19us : sub_preempt_count <-_raw_spin_unlock_irqrestore
    <idle>-0       3dN.1   19us : hrtimer_forward <-tick_nohz_idle_exit
    <idle>-0       3dN.1   20us : ktime_add_safe <-hrtimer_forward
    <idle>-0       3dN.1   20us : ktime_add_safe <-hrtimer_forward
    <idle>-0       3dN.1   20us : hrtimer_start_range_ns <-hrtimer_start_expires.constprop.11
    <idle>-0       3dN.1   20us : __hrtimer_start_range_ns <-hrtimer_start_range_ns
    <idle>-0       3dN.1   21us : lock_hrtimer_base.isra.18 <-__hrtimer_start_range_ns
    <idle>-0       3dN.1   21us : _raw_spin_lock_irqsave <-lock_hrtimer_base.isra.18
    <idle>-0       3dN.1   21us : add_preempt_count <-_raw_spin_lock_irqsave
    <idle>-0       3dN.2   22us : ktime_add_safe <-__hrtimer_start_range_ns
    <idle>-0       3dN.2   22us : enqueue_hrtimer <-__hrtimer_start_range_ns
    <idle>-0       3dN.2   22us : tick_program_event <-__hrtimer_start_range_ns
    <idle>-0       3dN.2   23us : clockevents_program_event <-tick_program_event
    <idle>-0       3dN.2   23us : ktime_get <-clockevents_program_event
    <idle>-0       3dN.2   23us : lapic_next_event <-clockevents_program_event
    <idle>-0       3dN.2   24us : _raw_spin_unlock_irqrestore <-__hrtimer_start_range_ns
    <idle>-0       3dN.2   24us : sub_preempt_count <-_raw_spin_unlock_irqrestore
    <idle>-0       3dN.1   24us : account_idle_ticks <-tick_nohz_idle_exit
    <idle>-0       3dN.1   24us : account_idle_time <-account_idle_ticks
    <idle>-0       3.N.1   25us : sub_preempt_count <-cpu_idle
    <idle>-0       3.N..   25us : schedule <-cpu_idle
    <idle>-0       3.N..   25us : __schedule <-preempt_schedule
    <idle>-0       3.N..   26us : add_preempt_count <-__schedule
    <idle>-0       3.N.1   26us : rcu_note_context_switch <-__schedule
    <idle>-0       3.N.1   26us : rcu_sched_qs <-rcu_note_context_switch
    <idle>-0       3dN.1   27us : rcu_preempt_qs <-rcu_note_context_switch
    <idle>-0       3.N.1   27us : _raw_spin_lock_irq <-__schedule
    <idle>-0       3dN.1   27us : add_preempt_count <-_raw_spin_lock_irq
    <idle>-0       3dN.2   28us : put_prev_task_idle <-__schedule
    <idle>-0       3dN.2   28us : pick_next_task_stop <-pick_next_task
    <idle>-0       3dN.2   28us : pick_next_task_rt <-pick_next_task
    <idle>-0       3dN.2   29us : dequeue_pushable_task <-pick_next_task_rt
    <idle>-0       3d..3   29us : __schedule <-preempt_schedule
    <idle>-0       3d..3   30us :      0:120:R ==> [003]  2448: 94:R sleep

Трек даже при отслеживании функций не слишком велик и приведен здесь полностью.

Прерывание произошло в момент бездействия системы. Где-то перед вызовом task_woken_rt() был установлен флаг NEED_RESCHED, что показано первым включением символа N.

Трассировка задержки и события

Трассировка функций может вносить значительные задержки, но без нее трудно установить причины задержки. Золотой серединой является включение трассировки событий, как показано ниже.

  # echo 0 > options/function-trace
  # echo wakeup_rt > current_tracer
  # echo 1 > events/enable
  # echo 1 > tracing_on
  # echo 0 > tracing_max_latency
  # chrt -f 5 sleep 1
  # echo 0 > tracing_on
  # cat trace
  # tracer: wakeup_rt
  #
  # wakeup_rt latency trace v1.1.5 on 3.8.0-test+
  # --------------------------------------------------------------------
  # latency: 6 us, #12/12, CPU#2 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
  #    -----------------
  #    | task: sleep-5882 (uid:0 nice:0 policy:1 rt_prio:5)
  #    -----------------
  #
  #                  _------=> CPU#            
  #                 / _-----=> irqs-off        
  #                | / _----=> need-resched    
  #                || / _---=> hardirq/softirq 
  #                ||| / _--=> preempt-depth   
  #                |||| /     delay             
  #  cmd     pid   ||||| time  |   caller      
  #     \   /      |||||  \    |   /           
    <idle>-0       2d.h4    0us :      0:120:R   + [002]  5882: 94:R sleep
    <idle>-0       2d.h4    0us : ttwu_do_activate.constprop.87 <-try_to_wake_up
    <idle>-0       2d.h4    1us : sched_wakeup: comm=sleep pid=5882 prio=94 success=1 target_cpu=002
    <idle>-0       2dNh2    1us : hrtimer_expire_exit: hrtimer=ffff88007796feb8
    <idle>-0       2.N.2    2us : power_end: cpu_id=2
    <idle>-0       2.N.2    3us : cpu_idle: state=4294967295 cpu_id=2
    <idle>-0       2dN.3    4us : hrtimer_cancel: hrtimer=ffff88007d50d5e0
    <idle>-0       2dN.3    4us : hrtimer_start: hrtimer=ffff88007d50d5e0 function=tick_sched_timer expires=34311211000000 softexpires=34311211000000
    <idle>-0       2.N.2    5us : rcu_utilization: Start context switch
    <idle>-0       2.N.2    5us : rcu_utilization: End context switch
    <idle>-0       2d..3    6us : __schedule <-schedule
    <idle>-0       2d..3    6us :      0:120:R ==> [002]  5882: 94:R sleep

Определение аппаратной задержки

Для определения задержек в оборудовании служит трассировщик hwlat. Следует отметить, что этот трассировщик влияет на производительность всей системы и может полностью загружать CPU с запретом прерываний.

  # echo hwlat > current_tracer
  # sleep 100
  # cat trace
  # tracer: hwlat
  #
  #                              _-----=> irqs-off
  #                             / _----=> need-resched
  #                            | / _---=> hardirq/softirq
  #                            || / _--=> preempt-depth
  #                            ||| /     delay
  #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
  #              | |       |   ||||       |         |
             <...>-3638  [001] d... 19452.055471: #1     inner/outer(us):   12/14    ts:1499801089.066141940
             <...>-3638  [003] d... 19454.071354: #2     inner/outer(us):   11/9     ts:1499801091.082164365
             <...>-3638  [002] dn.. 19461.126852: #3     inner/outer(us):   12/9     ts:1499801098.138150062
             <...>-3638  [001] d... 19488.340960: #4     inner/outer(us):    8/12    ts:1499801125.354139633
             <...>-3638  [003] d... 19494.388553: #5     inner/outer(us):    8/12    ts:1499801131.402150961
             <...>-3638  [003] d... 19501.283419: #6     inner/outer(us):    0/12    ts:1499801138.297435289 nmi-total:4 nmi-count:1

Приведенный выше вывод содержит заголовок с описанием формата. Для всех событий прерывания запрещены (d). Вывод в колонке FUNCTION описан ниже.

#1

Число записанных событий, превышающих tracing_threshold (см. ниже).

inner/outer(us): 12/14

Два значения, показывающие внутреннюю (inner) и внешнюю (outer) задержку. Тест выполняется в цикле, проверяя временную метку дважды. Задержка между двумя метками одного цикла называется внутренней, а задержка между меткой предыдущего и текущего циклов — внешней.

ts:1499801089.066141940

Метка абсолютного времени события.

nmi-total:4 nmi-count:1

Для поддерживающей немаскируемые прерывания архитектуры при NMI в процессе тестирования время, проведенное в NMI, указывается в поле nmi-total (мксек).

Если архитектура поддерживает NMI, поле nmi-count будет показывать число NMI в процессе тестирования.

Файлы hwlat

tracing_thresh

Если в этом файле указано значение 0, автоматически устанавливается значение 10 (мксек), определяющее порог задержки, которая вызывает запись трассировки в кольцевой буфер.

Отметим, что по завершении трассировщика hwlat (записи другого трассировщика в current_tracer) в файле восстанавливается исходное значение tracing_threshold.

hwlat_detector/width

Продолжительность работы теста с отключенными прерываниями.

hwlat_detector/window

Продолжительность окна тестирования — тест выполнялся в течение width мксек в течение window мксек.

tracing_cpumask

При запуске теста создается поток (thread) ядра для работы теста. Этот поток будет передаваться между CPU, указанными в tracing_cpumask каждый интервал (окно — window). Для работы теста на определенных CPU в этом файле устанавливается нужная маска.

Трассировщик function

Этот трассировщик отслеживает функции. Включить трассировщик можно через файловую систему debugfs. Следует убедиться, что установлена переменная (файл) ftrace_enabled, поскольку в противном случае трассировка не будет делать ничего (см. ftrace_enabled ниже).

Ниже приведен пример команд и вывода при трассировке функций.

  # sysctl kernel.ftrace_enabled=1
  # echo function > current_tracer
  # echo 1 > tracing_on
  # usleep 1
  # echo 0 > tracing_on
  # cat trace
  # tracer: function
  #
  # entries-in-buffer/entries-written: 24799/24799   #P:4
  #
  #                              _-----=> irqs-off
  #                             / _----=> need-resched
  #                            | / _---=> hardirq/softirq
  #                            || / _--=> preempt-depth
  #                            ||| /     delay
  #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
  #              | |       |   ||||       |         |
              bash-1994  [002] ....  3082.063030: mutex_unlock <-rb_simple_write
              bash-1994  [002] ....  3082.063031: __mutex_unlock_slowpath <-mutex_unlock
              bash-1994  [002] ....  3082.063031: __fsnotify_parent <-fsnotify_modify
              bash-1994  [002] ....  3082.063032: fsnotify <-fsnotify_modify
              bash-1994  [002] ....  3082.063032: __srcu_read_lock <-fsnotify
              bash-1994  [002] ....  3082.063032: add_preempt_count <-__srcu_read_lock
              bash-1994  [002] ...1  3082.063032: sub_preempt_count <-__srcu_read_lock
              bash-1994  [002] ....  3082.063033: __srcu_read_unlock <-fsnotify

Примечание. Трассировщик функций использует кольцевые буферы для хранения показанных выше записей и новые данные могут переписывать более старые. Иногда использования команды echo не достаточно для прекращения трассировки, поскольку данные могут быть перезаписаны. По этой причине иногда лучше отключать трассировку из программы. Это позволит остановить трассировку в нужной точке. Для выключения трассировки непосредственно из программы на языке C можно воспользоваться кодом, подобным приведенному ниже.

	int trace_fd;
	[...]
	int main(int argc, char *argv[]) {
		[...]
		trace_fd = open(tracing_file("tracing_on"), O_WRONLY);
		[...]
		if (condition_hit()) {
			write(trace_fd, "0", 1);
		}
		[...]
	}

Трассировка одного потока

Путем записи нужного значения в файл set_ftrace_pid можно ограничиться отслеживанием одного потока (thread).

  # cat set_ftrace_pid
  no pid
  # echo 3111 > set_ftrace_pid
  # cat set_ftrace_pid
  3111
  # echo function > current_tracer
  # cat trace | head
  # tracer: function
  #
  #           TASK-PID    CPU#    TIMESTAMP  FUNCTION
  #              | |       |          |         |
      yum-updatesd-3111  [003]  1637.254676: finish_task_switch <-thread_return
      yum-updatesd-3111  [003]  1637.254681: hrtimer_cancel <-schedule_hrtimeout_range
      yum-updatesd-3111  [003]  1637.254682: hrtimer_try_to_cancel <-hrtimer_cancel
      yum-updatesd-3111  [003]  1637.254683: lock_hrtimer_base <-hrtimer_try_to_cancel
      yum-updatesd-3111  [003]  1637.254685: fget_light <-do_sys_poll
      yum-updatesd-3111  [003]  1637.254686: pipe_poll <-do_sys_poll
  # echo > set_ftrace_pid
  # cat trace |head
  # tracer: function
  #
  #           TASK-PID    CPU#    TIMESTAMP  FUNCTION
  #              | |       |          |         |
  ##### CPU 3 buffer started ####
      yum-updatesd-3111  [003]  1701.957688: free_poll_entry <-poll_freewait
      yum-updatesd-3111  [003]  1701.957689: remove_wait_queue <-free_poll_entry
      yum-updatesd-3111  [003]  1701.957691: fput <-free_poll_entry
      yum-updatesd-3111  [003]  1701.957692: audit_syscall_exit <-sysret_audit
      yum-updatesd-3111  [003]  1701.957693: path_put <-audit_syscall_exit

Если нужно отслеживать функцию при выполнении, можно воспользоваться чем-то вроде приведенной программы.

	#include <stdio.h>
	#include <stdlib.h>
	#include <sys/types.h>
	#include <sys/stat.h>
	#include <fcntl.h>
	#include <unistd.h>
	#include <string.h>

	#define _STR(x) #x
	#define STR(x) _STR(x)
	#define MAX_PATH 256

	const char *find_tracefs(void)
	{
	       static char tracefs[MAX_PATH+1];
	       static int tracefs_found;
	       char type[100];
	       FILE *fp;

	       if (tracefs_found)
		       return tracefs;

	       if ((fp = fopen("/proc/mounts","r")) == NULL) {
		       perror("/proc/mounts");
		       return NULL;
	       }

	       while (fscanf(fp, "%*s %"
		             STR(MAX_PATH)
		             "s %99s %*s %*d %*d\n",
		             tracefs, type) == 2) {
		       if (strcmp(type, "tracefs") == 0)
		               break;
	       }
	       fclose(fp);

	       if (strcmp(type, "tracefs") != 0) {
		       fprintf(stderr, "tracefs not mounted");
		       return NULL;
	       }

	       strcat(tracefs, "/tracing/");
	       tracefs_found = 1;

	       return tracefs;
	}

	const char *tracing_file(const char *file_name)
	{
	       static char trace_file[MAX_PATH+1];
	       snprintf(trace_file, MAX_PATH, "%s/%s", find_tracefs(), file_name);
	       return trace_file;
	}

	int main (int argc, char **argv)
	{
		if (argc < 1)
		        exit(-1);

		if (fork() > 0) {
		        int fd, ffd;
		        char line[64];
		        int s;

		        ffd = open(tracing_file("current_tracer"), O_WRONLY);
		        if (ffd < 0)
		                exit(-1);
		        write(ffd, "nop", 3);

		        fd = open(tracing_file("set_ftrace_pid"), O_WRONLY);
		        s = sprintf(line, "%d\n", getpid());
		        write(fd, line, s);

		        write(ffd, "function", 8);

		        close(fd);
		        close(ffd);

		        execvp(argv[1], argv+1);
		}

		return 0;
	}

Подойдет также простой сценарий, показанный ниже.

  #!/bin/bash

  tracefs=`sed -ne 's/^tracefs \(.*\) tracefs.*/\1/p' /proc/mounts`
  echo nop > $tracefs/tracing/current_tracer
  echo 0 > $tracefs/tracing/tracing_on
  echo $$ > $tracefs/tracing/set_ftrace_pid
  echo function > $tracefs/tracing/current_tracer
  echo 1 > $tracefs/tracing/tracing_on
  exec "$@"

Трассировщик function_graph

Этот трассировщик похож на function, но проверяет функции на входе и выходе. Это делается с помощью динамически выделяемого стека адресов возврата в каждой task_struct. На входе функции трассировщик переписывает адрес возврата каждой отслеживаемой функции для установки специального «зонда». Исходный адрес возврата сохраняется в стеке возврата структуры task_struct.

Зондирование на входе и выходе функции позволяет определить время ее выполнения и получить надежный стек вызовов для создания графа вызовов функций.

Этот трассировщик полезен в нескольких ситуациях:

  • поиск причин странного поведения ядра;

  • обнаружение непонятных задержек;

  • быстрый поиск пути выполнение определенной функции;

  • исследование происходящего внутри ядра.

  # tracer: function_graph
  #
  # CPU  DURATION                  FUNCTION CALLS
  # |     |   |                     |   |   |   |

   0)               |  sys_open() {
   0)               |    do_sys_open() {
   0)               |      getname() {
   0)               |        kmem_cache_alloc() {
   0)   1.382 us    |          __might_sleep();
   0)   2.478 us    |        }
   0)               |        strncpy_from_user() {
   0)               |          might_fault() {
   0)   1.389 us    |            __might_sleep();
   0)   2.553 us    |          }
   0)   3.807 us    |        }
   0)   7.876 us    |      }
   0)               |      alloc_fd() {
   0)   0.668 us    |        _spin_lock();
   0)   0.570 us    |        expand_files();
   0)   0.586 us    |        _spin_unlock();

Здесь имеется несколько колонок, которые можно динамически включать и выключать. Можно использовать любую подходящую комбинацию опций.

  • Номер процессора, на котором выполняется функция, по умолчанию выводится. Иногда может потребоваться отслеживание лишь одного процессора (см. файл tracing_cpu_mask) или отслеживать функции без привязки к процессорам.

    • Скрыть номер процессора — echo nofuncgraph-cpu > trace_options.

    • Показывать номер процессора — echo funcgraph-cpu > trace_options.

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

    • Скрыть продолжительность вызова — echo nofuncgraph-duration > trace_options.

    • Показывать продолжительность вызова — echo funcgraph-duration > trace_options.

  • Поле служебных данных (overhead) указывается перед полем продолжительности в случае достижения порога длительности.

    • Скрыть служебные данные — echo nofuncgraph-overhead > trace_options.

    • Показывать служебные данные — echo funcgraph-overhead > trace_options

    3) # 1837.709 us |          } /* __switch_to */
    3)               |          finish_task_switch() {
    3)   0.313 us    |            _raw_spin_unlock_irq();
    3)   3.177 us    |          }
    3) # 1889.063 us |        } /* __schedule */
    3) ! 140.417 us  |      } /* __schedule */
    3) # 2034.948 us |    } /* schedule */
    3) * 33998.59 us |  } /* schedule_preempt_disabled */

    [...]

    1)   0.260 us    |              msecs_to_jiffies();
    1)   0.313 us    |              __rcu_read_unlock();
    1) + 61.770 us   |            }
    1) + 64.479 us   |          }
    1)   0.313 us    |          rcu_bh_qs();
    1)   0.313 us    |          __local_bh_enable();
    1) ! 217.240 us  |        }
    1)   0.365 us    |        idle_cpu();
    1)               |        rcu_irq_exit() {
    1)   0.417 us    |          rcu_eqs_enter_common.isra.47();
    1)   3.125 us    |        }
    1) ! 227.812 us  |      }
    1) ! 457.395 us  |    }
    1) @ 119760.2 us |  }

    [...]

    2)               |    handle_IPI() {
    1)   6.979 us    |                  }
    2)   0.417 us    |      scheduler_ipi();
    1)   9.791 us    |                }
    1) + 12.917 us   |              }
    2)   3.490 us    |    }
    1) + 15.729 us   |            }
    1) + 18.542 us   |          }
    2) $ 3594274 us  |  }

Маркеры продолжительности

+ — больше 10 мксек.

! — больше 100 мксек.

# — больше 1000 мксек.

* — больше 10 мсек.

@ — больше 100 мсек.

$ — больше 1 сек.

  • Поле task/pid показывает строку команды и pid процесса, в котором функция выполняется. По умолчанию это поле не выводится.

    • Скрыть поле — echo nofuncgraph-proc > trace_options.

    • Показывать поле — echo funcgraph-proc > trace_options.

    # tracer: function_graph
    #
    # CPU  TASK/PID        DURATION                  FUNCTION CALLS
    # |    |    |           |   |                     |   |   |   |
    0)    sh-4802     |               |                  d_free() {
    0)    sh-4802     |               |                    call_rcu() {
    0)    sh-4802     |               |                      __call_rcu() {
    0)    sh-4802     |   0.616 us    |                        rcu_process_gp_end();
    0)    sh-4802     |   0.586 us    |                        check_for_new_grace_period();
    0)    sh-4802     |   2.899 us    |                      }
    0)    sh-4802     |   4.040 us    |                    }
    0)    sh-4802     |   5.151 us    |                  }
    0)    sh-4802     | + 49.370 us   |                }
  • Поле «абсолютного» времени содержит временную метку системных часов, отсчитываемую от момента загрузки системы. Время указывается на входе и выходе функции.

    • Скрыть время — echo nofuncgraph-abstime > trace_options

    • Показывать время — echo funcgraph-abstime > trace_options

    #
    #      TIME       CPU  DURATION                  FUNCTION CALLS
    #       |         |     |   |                     |   |   |   |
    360.774522 |   1)   0.541 us    |                                          }
    360.774522 |   1)   4.663 us    |                                        }
    360.774523 |   1)   0.541 us    |                                        __wake_up_bit();
    360.774524 |   1)   6.796 us    |                                      }
    360.774524 |   1)   7.952 us    |                                    }
    360.774525 |   1)   9.063 us    |                                  }
    360.774525 |   1)   0.615 us    |                                  journal_mark_dirty();
    360.774527 |   1)   0.578 us    |                                  __brelse();
    360.774528 |   1)               |                                  reiserfs_prepare_for_journal() {
    360.774528 |   1)               |                                    unlock_buffer() {
    360.774529 |   1)               |                                      wake_up_bit() {
    360.774529 |   1)               |                                        bit_waitqueue() {
    360.774530 |   1)   0.594 us    |                                          __phys_addr();

Имя функции, начало которой не попадает в буфер трассировки выводится после закрывающей скобки для функции. Вывод этого имени можно включить для упрощения поиска продолжительности функций с помощью grep. По умолчанию вывод отключен

  • Скрыть имя — echo nofuncgraph-tail > trace_options.

  • Показывать имя — echo funcgraph-tail > trace_options.

Пример без вывода имен (nofuncgraph-tail), как принято по умолчанию.

    0)               |      putname() {
    0)               |        kmem_cache_free() {
    0)   0.518 us    |          __phys_addr();
    0)   1.757 us    |        }
    0)   2.861 us    |      }

Пример с выводом имен (funcgraph-tail)

    0)               |      putname() {
    0)               |        kmem_cache_free() {
    0)   0.518 us    |          __phys_addr();
    0)   1.757 us    |        } /* kmem_cache_free() */
    0)   2.861 us    |      } /* putname() */

Можно добавить комментарии к конкретным функциям с помощью trace_printk(). Например, для включения комментариев в функцию __might_sleep() достаточно включить файл <linux/ftrace.h> и вызвать trace_printk() внутри __might_sleep(). Например,

	trace_printk("I'm a comment!\n")

будет давать вывод

   1)               |             __might_sleep() {
   1)               |                /* I'm a comment! */
   1)   1.449 us    |             }

Другие варианты применения этого трассировщика описаны в следующем разделе.


Динамическая трассировка ftrace

Если установлена опция ядра CONFIG_DYNAMIC_FTRACE, система будет работать почти без связанных с трассировкой издержек при отключенной трассировке функций. Это работает за счет вызова функции mcount (помещается в начале каждой функции ядра с помощью опции -pg компилятора gcc6), указывающей простой возврат.

При компиляции каждый объект файла C запускается через программу recordmcount (находится в каталоге scripts), которая анализирует заголовки ELF в объекте C для поиска всех вызовов в разделе .text, вызывающих функцию mcount7.

Отметим, что отслеживаются не все разделы — трассировка может быть отключена notrace или заблокирована иным путем и все встроенные функции не будут отслеживаться. Для просмотра списка функций, которые могут трассироваться, следует обратиться к файлу available_filter_functions.

Создается раздел __mcount_loc, в котором содержатся ссылки на все вызовы mcount/fentry в разделе .text. Программа recordmcount заново связывает этот раздел с исходными объектами. На этапе финальной компоновки ядра все эти ссылки будут добавлены в одну таблицу.

При загрузке (до инициализации SMP) динамический код ftrace сканирует эту таблицу и заменяет все найденные ссылки на nop, а также записывает местоположения, добавленные в список available_filter_functions. Модули обрабатываются по мере их загрузки до начала выполнения. При выгрузке модуля реализованные в нем функции удаляются из списка функций ftrace. Эту процедуру автоматически выполняет код выгрузки модулей и автор модуля не должен беспокоиться об этом.

При включенной трассировке процесс изменения точек трассировки функций зависит от архитектуры. Старый метод использовал kstop_machine для предотвращения «гонок» CPU, выполняющих измененный код (что может заставлять CPU делать нежелательные вещи, особенно в тех случаях, когда измененный код пересекает границу кэше или страницы) и операции nop обратно помещались в вызовы. Но сейчас вместо mcount (сейчас это просто функция-заглушка) используются вызовы инфраструктуры ftrace.

Новый метод изменения точек трассировки функций заключается в размещении точки остановки (breakpoint) в изменяемом месте, синхронизации всех CPU, и изменении остальной части инструкции, не охваченной точкой остановки. CPU синхронизируются еще раз и точка установки удаляется из окончательной версии.

Некоторым вариантам архитектуры не нужно заботиться о синхронизации, они просто могут поместить новый код взамен прежнего без возникновения проблем с другими CPU, работающими в это же время.

Одним из побочных эффектов записи функций, которые будут отслеживаться, является то, что можно выбрать функции, которые мы хотим трассировать, и функции, для которых хотим, чтобы вызовы mcount оставались nop.

Используется два файла, один из которых служит для разрешения, другой для запрета трассировки заданных функций

  set_ftrace_filter

и

  set_ftrace_notrace

Список функций, которые можно включить в эти файлы содержится в файле available_filter_functions.

  # cat available_filter_functions
  put_prev_task_idle
  kmem_cache_create
  pick_next_task_rt
  get_online_cpus
  pick_next_task_fair
  mutex_lock
  [...]

Если интересно отслеживать лишь sys_nanosleep и hrtimer_interrupt, можно воспользоваться приведенными ниже командами.

  # echo sys_nanosleep hrtimer_interrupt > set_ftrace_filter
  # echo function > current_tracer
  # echo 1 > tracing_on
  # usleep 1
  # echo 0 > tracing_on
  # cat trace
  # tracer: function
  #
  # entries-in-buffer/entries-written: 5/5   #P:4
  #
  #                              _-----=> irqs-off
  #                             / _----=> need-resched
  #                            | / _---=> hardirq/softirq
  #                            || / _--=> preempt-depth
  #                            ||| /     delay
  #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
  #              | |       |   ||||       |         |
            usleep-2665  [001] ....  4186.475355: sys_nanosleep <-system_call_fastpath
            <idle>-0     [001] d.h1  4186.475409: hrtimer_interrupt <-smp_apic_timer_interrupt
            usleep-2665  [001] d.h1  4186.475426: hrtimer_interrupt <-smp_apic_timer_interrupt
            <idle>-0     [003] d.h1  4186.475426: hrtimer_interrupt <-smp_apic_timer_interrupt
            <idle>-0     [002] d.h1  4186.475427: hrtimer_interrupt <-smp_apic_timer_interrupt

Для просмотра функций, которые будут отслеживаться, можно воспользоваться командой

  # cat set_ftrace_filter
  hrtimer_interrupt
  sys_nanosleep

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

match*

соответствует всем функциям, начинающимся с match.

*match

соответствует всем функциям, заканчивающимся match.

*match*

соответствует всем функциям, содержащим match в имени.

match1*match2

соответствует всем функциям, начинающимся с match1 и заканчивающимися match2.

Примечание. Шаблоны сопоставления лучше указывать в кавычках, поскольку в противном случае интерпретатор команд может счесть параметры именами файлов в локальном каталоге.

Например,

  # echo 'hrtimer_*' > set_ftrace_filter

Приведет к выводу, показанному ниже

  # tracer: function
  #
  # entries-in-buffer/entries-written: 897/897   #P:4
  #
  #                              _-----=> irqs-off
  #                             / _----=> need-resched
  #                            | / _---=> hardirq/softirq
  #                            || / _--=> preempt-depth
  #                            ||| /     delay
  #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
  #              | |       |   ||||       |         |
            <idle>-0     [003] dN.1  4228.547803: hrtimer_cancel <-tick_nohz_idle_exit
            <idle>-0     [003] dN.1  4228.547804: hrtimer_try_to_cancel <-hrtimer_cancel
            <idle>-0     [003] dN.2  4228.547805: hrtimer_force_reprogram <-__remove_hrtimer
            <idle>-0     [003] dN.1  4228.547805: hrtimer_forward <-tick_nohz_idle_exit
            <idle>-0     [003] dN.1  4228.547805: hrtimer_start_range_ns <-hrtimer_start_expires.constprop.11
            <idle>-0     [003] d..1  4228.547858: hrtimer_get_next_event <-get_next_timer_interrupt
            <idle>-0     [003] d..1  4228.547859: hrtimer_start <-__tick_nohz_idle_enter
            <idle>-0     [003] d..2  4228.547860: hrtimer_force_reprogram <-__rem

Отметим, что трассировка sys_nanosleep была потеряна.

  # cat set_ftrace_filter
  hrtimer_run_queues
  hrtimer_run_pending
  hrtimer_init
  hrtimer_cancel
  hrtimer_try_to_cancel
  hrtimer_forward
  hrtimer_start
  hrtimer_reprogram
  hrtimer_force_reprogram
  hrtimer_get_next_event
  hrtimer_interrupt
  hrtimer_nanosleep
  hrtimer_wakeup
  hrtimer_get_remaining
  hrtimer_get_res
  hrtimer_init_sleeper

Причиной этого стало указание символа > в команде echo. Одиночная угловая скобка (>) задает переписывание файла, а два символа (>>) указывают добавление в конец файла.

Для сброса фильтров с восстановлением записи всех функций можно воспользоваться командой

 # echo > set_ftrace_filter
 # cat set_ftrace_filter
 #

Далее показано, как можно добавить фильтры, не удаляя имеющихся.

  # echo sys_nanosleep > set_ftrace_filter
  # cat set_ftrace_filter
  sys_nanosleep
  # echo 'hrtimer_*' >> set_ftrace_filter
  # cat set_ftrace_filter
  hrtimer_run_queues
  hrtimer_run_pending
  hrtimer_init
  hrtimer_cancel
  hrtimer_try_to_cancel
  hrtimer_forward
  hrtimer_start
  hrtimer_reprogram
  hrtimer_force_reprogram
  hrtimer_get_next_event
  hrtimer_interrupt
  sys_nanosleep
  hrtimer_nanosleep
  hrtimer_wakeup
  hrtimer_get_remaining
  hrtimer_get_res
  hrtimer_init_sleeper

Фильтр set_ftrace_notrace исключает трассировку указанных в файле функций. Например, команда

  # echo '*preempt*' '*lock*' > set_ftrace_notrace

Приведет к показанному ниже результату.

  # tracer: function
  #
  # entries-in-buffer/entries-written: 39608/39608   #P:4
  #
  #                              _-----=> irqs-off
  #                             / _----=> need-resched
  #                            | / _---=> hardirq/softirq
  #                            || / _--=> preempt-depth
  #                            ||| /     delay
  #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
  #              | |       |   ||||       |         |
              bash-1994  [000] ....  4342.324896: file_ra_state_init <-do_dentry_open
              bash-1994  [000] ....  4342.324897: open_check_o_direct <-do_last
              bash-1994  [000] ....  4342.324897: ima_file_check <-do_last
              bash-1994  [000] ....  4342.324898: process_measurement <-ima_file_check
              bash-1994  [000] ....  4342.324898: ima_get_action <-process_measurement
              bash-1994  [000] ....  4342.324898: ima_match_policy <-ima_get_action
              bash-1994  [000] ....  4342.324899: do_truncate <-do_last
              bash-1994  [000] ....  4342.324899: should_remove_suid <-do_truncate
              bash-1994  [000] ....  4342.324899: notify_change <-do_truncate
              bash-1994  [000] ....  4342.324900: current_fs_time <-notify_change
              bash-1994  [000] ....  4342.324900: current_kernel_time <-current_fs_time
              bash-1994  [000] ....  4342.324900: timespec_trunc <-current_fs_time

Откуда можно видеть, что отслеживания lock и preempt не происходит.

Динамическая трассировка с function_graph

Хотя приведенные выше разъяснения относятся к обоим трассировщикам function и function_graph, последний имеет некоторые особые возможности.

Если вы хотите отслеживать лишь одну функцию и всех ее потомком, достаточно включить имя этой функции с помощью команды echo в файл set_graph_function. Например,

 echo __do_fault > set_graph_function

будет выводить «расширенную» трассировку функции __do_fault().

   0)               |  __do_fault() {
   0)               |    filemap_fault() {
   0)               |      find_lock_page() {
   0)   0.804 us    |        find_get_page();
   0)               |        __might_sleep() {
   0)   1.329 us    |        }
   0)   3.904 us    |      }
   0)   4.979 us    |    }
   0)   0.653 us    |    _spin_lock();
   0)   0.578 us    |    page_add_file_rmap();
   0)   0.525 us    |    native_set_pte_at();
   0)   0.585 us    |    _spin_unlock();
   0)               |    unlock_page() {
   0)   0.541 us    |      page_waitqueue();
   0)   0.639 us    |      __wake_up_bit();
   0)   2.786 us    |    }
   0) + 14.237 us   |  }
   0)               |  __do_fault() {
   0)               |    filemap_fault() {
   0)               |      find_lock_page() {
   0)   0.698 us    |        find_get_page();
   0)               |        __might_sleep() {
   0)   1.412 us    |        }
   0)   3.950 us    |      }
   0)   5.098 us    |    }
   0)   0.631 us    |    _spin_lock();
   0)   0.571 us    |    page_add_file_rmap();
   0)   0.526 us    |    native_set_pte_at();
   0)   0.586 us    |    _spin_unlock();
   0)               |    unlock_page() {
   0)   0.533 us    |      page_waitqueue();
   0)   0.638 us    |      __wake_up_bit();
   0)   2.793 us    |    }
   0) + 14.012 us   |  }

Можно таким способом отслеживать несколько функций, например,

 echo sys_open > set_graph_function
 echo sys_close >> set_graph_function

Если после этого нужно вернуться к отслеживанию всех функций, можно сбросить фильтр командой

 echo > set_graph_function

ftrace_enabled

Следует отметить, что sysctl ftrace_enable служит основным выключателем для трассировщика функций, который по умолчанию включен (если трассировка функций активизирована в ядре). При отключении трассировки выключается отслеживание всех функций (не только трассировщики функций для ftrace, но и другие — perf, kprobe, трассировка стека, профилирование и т. п.). Следует осторожно относиться к запрету трассировки. Команды управления приведены ниже.

  sysctl kernel.ftrace_enabled=0
  sysctl kernel.ftrace_enabled=1

или

  echo 0 > /proc/sys/kernel/ftrace_enabled
  echo 1 > /proc/sys/kernel/ftrace_enabled

Команды фильтрации

Интерфейс set_ftrace_filter поддерживает несколько команд, имеющих формат

  <function>:<command>:<parameter>

Ниже перечислены поддерживаемые команды.

mod

Включает фильтрацию функций на уровне модуля, задаваемого параметром. Например, если нужно отслеживать лишь функции write* в модуле ext3, можно воспользоваться командой

   echo 'write*:mod:ext3' > set_ftrace_filter

Эта команда взаимодействует с фильтрами так же, как для фильтрации по именам функций, т. е. для добавления других функций применяется операция записи в конец файла (>>). Для удалении функции применяется восклицательный знак перед именем.

   echo '!writeback*:mod:ext3' >> set_ftrace_filter

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

   echo '!*:mod:!ext3' >> set_ftrace_filter

Для запрета трассировки всех модулей с сохранением трассировки ядра служит команд

   echo '!*:mod:*' >> set_ftrace_filter

Для фильтрации только функций ядра служат команды вида

   echo '*write*:mod:!*' >> set_ftrace_filter

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

   echo '*write*:mod:*snd*' >> set_ftrace_filter

traceon/traceoff

Эти команды включают и выключают трассировку только при обращении к указанным функциям. Параметр определяет число включений и отключений трассировки, при отсутствии параметра число не ограничивается. Например, для запрета трассировки при первых 5 вызовах __schedule_bug можно воспользоваться командой

   echo '__schedule_bug:traceoff:5' > set_ftrace_filter

Для запрета трассировки при вызове __schedule_bug служит команда

   echo '__schedule_bug:traceoff' > set_ftrace_filter

Эти команды являются накопительными независимо от их добавления в set_ftrace_filter. Для удаления команды указывается символ ! Перед ее именем и значение 0 для параметра

   echo '!__schedule_bug:traceoff:0' > set_ftrace_filter

Приведенная выше команда удаляет traceoff для функции __schedule_bug со счетчиком. Для удаления команд без счетчиков можно воспользоваться командой вида

   echo '!__schedule_bug:traceoff' > set_ftrace_filter

snapshot

Будет вызывать создание моментального снимка (snapshot) при вызове указанной функции.

   echo 'native_flush_tlb_others:snapshot' > set_ftrace_filter

Для однократного создания снимка служат команды вида

   echo 'native_flush_tlb_others:snapshot:1' > set_ftrace_filter

Для удаления приведенных выше команд можно воспользоваться командами

   echo '!native_flush_tlb_others:snapshot' > set_ftrace_filter
   echo '!native_flush_tlb_others:snapshot:0' > set_ftrace_filter

enable_event/disable_event

Эти команды могут включать и выключать трассировку событий. Отметим, что по причине «чувствительности» обратных вызовов трассировки функций при использовании этих команд точки трассировки активируются, но отключаются они в «мягком» (soft) режиме, т. е. точка трассировки будет вызываться, просто не будет отслеживаться ничего. Точка трассировки события остается в таком режиме, пока есть использующие ее команды.

   echo 'try_to_wake_up:enable_event:sched:sched_switch:2' > set_ftrace_filter

Формат команд показан ниже.

    <function>:enable_event:<system>:<event>[:count]
    <function>:disable_event:<system>:<event>[:count]

Для удаления связанных с событиями команд служат приведенные ниже команды

   echo '!try_to_wake_up:enable_event:sched:sched_switch:0' > set_ftrace_filter
   echo '!schedule:disable_event:sched:sched_switch' > set_ftrace_filter

dump

При обращении к функции на консоль будет выводиться содержимое кольцевого буфера ftrace. Это полезно при отладке, когда вы хотите быстро увидеть трассировку при обращении к некой функции. Например, ее можно использовать для просмотра буфера перед повторяющимся отказом.

cpudump

При обращении к функции на консоль будет выводиться содержимое кольцевого буфера ftrace для текущего CPU. В отличие от команды dump выводиться будет лишь буфер CPU, на котором выполняется вызвавшая вывод функция.

trace_pipe

Файл trace_pipe выводит те же данные, что и trace, но влияние на трассировку различается. Каждая запись из trace_pipe «потребляется» при считывании, т. е. последовательные операции чтения будут давать новый результат.

  # echo function > current_tracer
  # cat trace_pipe > /tmp/trace.out &
  [1] 4153
  # echo 1 > tracing_on
  # usleep 1
  # echo 0 > tracing_on
  # cat trace
  # tracer: function
  #
  # entries-in-buffer/entries-written: 0/0   #P:4
  #
  #                              _-----=> irqs-off
  #                             / _----=> need-resched
  #                            | / _---=> hardirq/softirq
  #                            || / _--=> preempt-depth
  #                            ||| /     delay
  #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
  #              | |       |   ||||       |         |

  #
  # cat /tmp/trace.out
             bash-1994  [000] ....  5281.568961: mutex_unlock <-rb_simple_write
             bash-1994  [000] ....  5281.568963: __mutex_unlock_slowpath <-mutex_unlock
             bash-1994  [000] ....  5281.568963: __fsnotify_parent <-fsnotify_modify
             bash-1994  [000] ....  5281.568964: fsnotify <-fsnotify_modify
             bash-1994  [000] ....  5281.568964: __srcu_read_lock <-fsnotify
             bash-1994  [000] ....  5281.568964: add_preempt_count <-__srcu_read_lock
             bash-1994  [000] ...1  5281.568965: sub_preempt_count <-__srcu_read_lock
             bash-1994  [000] ....  5281.568965: __srcu_read_unlock <-fsnotify
             bash-1994  [000] ....  5281.568967: sys_dup2 <-system_call_fastpath

Отметим, что чтение файла trace_pipe будет блокироваться, пока в него не добавлено новых данных.

Записи трассировки

При диагностике проблем в ядре избыток или недостаток данных могут создавать проблемы. Файл buffer_size_kb служит для изменения размера внутренних буферов трассировки. Значение в файле указывает число записей, которые могут быть созданы для каждого CPU. Для определения полного размера это значение следует умножить на число процессоров.

  # cat buffer_size_kb
  1408 (units kilobytes)

Или просто прочитать файл buffer_total_size_kb

  # cat buffer_total_size_kb 
  5632

Для изменения размера буфера просто записывается (echo) нужное число (в сегментах по 1024 байта).

  # echo 10000 > buffer_size_kb
  # cat buffer_size_kb
  10000 (units kilobytes)

При попытке указать слишком большой размер буферов сработает триггер Out-Of-Memory.

  # echo 1000000000000 > buffer_size_kb
  -bash: echo: write error: Cannot allocate memory
  # cat buffer_size_kb
  85

Буферы per_cpu можно изменять независимо, как показано ниже.

  # echo 10000 > per_cpu/cpu0/buffer_size_kb
  # echo 100 > per_cpu/cpu1/buffer_size_kb

При разных размерах буферов per_cpu файл buffer_size_kb на верхнем уровне просто покажет X.

  # cat buffer_size_kb
  X

В этом случае можно воспользоваться командой

  # cat buffer_total_size_kb 
  12916

Запись в buffer_size_kb верхнего уровня будет сбрасывать буферы всех процессоров к одному размеру.

Мгновенные снимки

Опция ядра CONFIG_TRACER_SNAPSHOT включает возможность создания «моментальных снимков» для всех трассировщиков, кроме трассировщиков задержки. Трассировщики задержки, записывающие максимальное значение (такие как irqsoff или wakeup), не могут использовать эту возможность, поскольку в них уже применяется внутренний механизм snapshot mechanism.

Снимок сохраняет текущий буфер трассировки в конкретный момент времени без остановки отслеживания. Ftrace заменяет текущий буфер запасным и трассировка продолжается в новый (ранее резервный) буфер.

Ниже указаны файлы tracefs (tracing), связанные с этой функцией.

snapshot

используется для записи и считывания моментального снимка. Запись (echo) 1 в этот файл ведет к созданию запасного буфера, записи снимка и последующему его считыванию в формате файла (см. раздел Файловая система). Считывание снимка и трассировка выполняются параллельно. Когда запасной буфер создан, запись (echo) 0 в файл освобождает буфер, а запись других (положительных) значений очищает содержимое снимка.

состояние/ввод

0

1

иное

Не выделен

Ничего

Выделение и переключение

Ничего

Выделен

Освобождение

swap

Очистка

Ниже приведен пример использования моментального снимка.

  # echo 1 > events/sched/enable
  # echo 1 > snapshot
  # cat snapshot
  # tracer: nop
  #
  # entries-in-buffer/entries-written: 71/71   #P:8
  #
  #                              _-----=> irqs-off
  #                             / _----=> need-resched
  #                            | / _---=> hardirq/softirq
  #                            || / _--=> preempt-depth
  #                            ||| /     delay
  #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
  #              | |       |   ||||       |         |
            <idle>-0     [005] d...  2440.603828: sched_switch: prev_comm=swapper/5 prev_pid=0 prev_prio=120   prev_state=R ==> next_comm=snapshot-test-2 next_pid=2242 next_prio=120
             sleep-2242  [005] d...  2440.603846: sched_switch: prev_comm=snapshot-test-2 prev_pid=2242 prev_prio=120   prev_state=R ==> next_comm=kworker/5:1 next_pid=60 next_prio=120
  [...]
          <idle>-0     [002] d...  2440.707230: sched_switch: prev_comm=swapper/2 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=snapshot-test-2 next_pid=2229 next_prio=120  

  # cat trace  
  # tracer: nop
  #
  # entries-in-buffer/entries-written: 77/77   #P:8
  #
  #                              _-----=> irqs-off
  #                             / _----=> need-resched
  #                            | / _---=> hardirq/softirq
  #                            || / _--=> preempt-depth
  #                            ||| /     delay
  #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
  #              | |       |   ||||       |         |
            <idle>-0     [007] d...  2440.707395: sched_switch: prev_comm=swapper/7 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=snapshot-test-2 next_pid=2243 next_prio=120
   snapshot-test-2-2229  [002] d...  2440.707438: sched_switch: prev_comm=snapshot-test-2 prev_pid=2229 prev_prio=120 prev_state=S ==> next_comm=swapper/2 next_pid=0 next_prio=120
  [...]

Если попытаться использовать функцию snapshot для одного из трассировщиков задержек, возникнет ошибка.

  # echo wakeup > current_tracer
  # echo 1 > snapshot
  bash: echo: write error: Device or resource busy
  # cat snapshot
  cat: snapshot: Device or resource busy

Экземпляры

В каталоге tracing файловой системы tracefs имеется папка instances, где можно создавать новые каталоги с помощью команды mkdir и удалять их командой rmdir. Создаваемые командой mkdir каталоги сразу будут содержать файлы и другие папки.

  # mkdir instances/foo
  # ls instances/foo
  buffer_size_kb  buffer_total_size_kb  events  free_buffer  per_cpu
  set_event  snapshot  trace  trace_clock  trace_marker  trace_options
  trace_pipe  tracing_on

Как видно из представленного вывода созданный каталог похож на сам каталог tracing. Фактически он отличается лишь тем, что буфер и события не зависят от основного экземпляра и других созданных экземпляров.

Файлы в новом каталоге работают так же, как одноименные файлы каталога tracing, за исключением того, что для них применяется независимый новый буфер. Файлы влияют на этот буфер, но не воздействуют на основной буфер (за исключением trace_options). В настоящее время trace_options одинаково влияет на все экземпляры, включая буфер верхнего уровня, но это может измениться в будущих версиях. Т. е. опции могут стать независимыми для каждого экземпляра.

Отмети, что здесь нет ни одного трассировщика функций, а также файлов current_tracer и available_tracers. Это обусловлено тем, что в настоящее буферы могут включать лишь разрешенные для них события.

  # mkdir instances/foo
  # mkdir instances/bar
  # mkdir instances/zoot
  # echo 100000 > buffer_size_kb
  # echo 1000 > instances/foo/buffer_size_kb
  # echo 5000 > instances/bar/per_cpu/cpu1/buffer_size_kb
  # echo function > current_trace
  # echo 1 > instances/foo/events/sched/sched_wakeup/enable
  # echo 1 > instances/foo/events/sched/sched_wakeup_new/enable
  # echo 1 > instances/foo/events/sched/sched_switch/enable
  # echo 1 > instances/bar/events/irq/enable
  # echo 1 > instances/zoot/events/syscalls/enable
  # cat trace_pipe
  CPU:2 [LOST 11745 EVENTS]
              bash-2044  [002] .... 10594.481032: _raw_spin_lock_irqsave <-get_page_from_freelist
              bash-2044  [002] d... 10594.481032: add_preempt_count <-_raw_spin_lock_irqsave
              bash-2044  [002] d..1 10594.481032: __rmqueue <-get_page_from_freelist
              bash-2044  [002] d..1 10594.481033: _raw_spin_unlock <-get_page_from_freelist
              bash-2044  [002] d..1 10594.481033: sub_preempt_count <-_raw_spin_unlock
              bash-2044  [002] d... 10594.481033: get_pageblock_flags_group <-get_pageblock_migratetype
              bash-2044  [002] d... 10594.481034: __mod_zone_page_state <-get_page_from_freelist
              bash-2044  [002] d... 10594.481034: zone_statistics <-get_page_from_freelist
              bash-2044  [002] d... 10594.481034: __inc_zone_state <-zone_statistics
              bash-2044  [002] d... 10594.481034: __inc_zone_state <-zone_statistics
              bash-2044  [002] .... 10594.481035: arch_dup_task_struct <-copy_process
  [...]
  # cat instances/foo/trace_pipe
              bash-1998  [000] d..4   136.676759: sched_wakeup: comm=kworker/0:1 pid=59 prio=120 success=1 target_cpu=000
              bash-1998  [000] dN.4   136.676760: sched_wakeup: comm=bash pid=1998 prio=120 success=1 target_cpu=000
            <idle>-0     [003] d.h3   136.676906: sched_wakeup: comm=rcu_preempt pid=9 prio=120 success=1 target_cpu=003
            <idle>-0     [003] d..3   136.676909: sched_switch: prev_comm=swapper/3 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=rcu_preempt next_pid=9 next_prio=120
       rcu_preempt-9     [003] d..3   136.676916: sched_switch: prev_comm=rcu_preempt prev_pid=9 prev_prio=120 prev_state=S ==> next_comm=swapper/3 next_pid=0 next_prio=120
              bash-1998  [000] d..4   136.677014: sched_wakeup: comm=kworker/0:1 pid=59 prio=120 success=1 target_cpu=000
              bash-1998  [000] dN.4   136.677016: sched_wakeup: comm=bash pid=1998 prio=120 success=1 target_cpu=000
              bash-1998  [000] d..3   136.677018: sched_switch: prev_comm=bash prev_pid=1998 prev_prio=120 prev_state=R+ ==> next_comm=kworker/0:1 next_pid=59 next_prio=120
       kworker/0:1-59    [000] d..4   136.677022: sched_wakeup: comm=sshd pid=1995 prio=120 success=1 target_cpu=001
       kworker/0:1-59    [000] d..3   136.677025: sched_switch: prev_comm=kworker/0:1 prev_pid=59 prev_prio=120 prev_state=S ==> next_comm=bash next_pid=1998 next_prio=120
  [...]
  # cat instances/bar/trace_pipe
       migration/1-14    [001] d.h3   138.732674: softirq_raise: vec=3 [action=NET_RX]
            <idle>-0     [001] dNh3   138.732725: softirq_raise: vec=3 [action=NET_RX]
              bash-1998  [000] d.h1   138.733101: softirq_raise: vec=1 [action=TIMER]
              bash-1998  [000] d.h1   138.733102: softirq_raise: vec=9 [action=RCU]
              bash-1998  [000] ..s2   138.733105: softirq_entry: vec=1 [action=TIMER]
              bash-1998  [000] ..s2   138.733106: softirq_exit: vec=1 [action=TIMER]
              bash-1998  [000] ..s2   138.733106: softirq_entry: vec=9 [action=RCU]
              bash-1998  [000] ..s2   138.733109: softirq_exit: vec=9 [action=RCU]
              sshd-1995  [001] d.h1   138.733278: irq_handler_entry: irq=21 name=uhci_hcd:usb4
              sshd-1995  [001] d.h1   138.733280: irq_handler_exit: irq=21 ret=unhandled
              sshd-1995  [001] d.h1   138.733281: irq_handler_entry: irq=21 name=eth0
              sshd-1995  [001] d.h1   138.733283: irq_handler_exit: irq=21 ret=handled
  [...]
  # cat instances/zoot/trace
  # tracer: nop
  #
  # entries-in-buffer/entries-written: 18996/18996   #P:4
  #
  #                              _-----=> irqs-off
  #                             / _----=> need-resched
  #                            | / _---=> hardirq/softirq
  #                            || / _--=> preempt-depth
  #                            ||| /     delay
  #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
  #              | |       |   ||||       |         |
              bash-1998  [000] d...   140.733501: sys_write -> 0x2
              bash-1998  [000] d...   140.733504: sys_dup2(oldfd: a, newfd: 1)
              bash-1998  [000] d...   140.733506: sys_dup2 -> 0x1
              bash-1998  [000] d...   140.733508: sys_fcntl(fd: a, cmd: 1, arg: 0)
              bash-1998  [000] d...   140.733509: sys_fcntl -> 0x1
              bash-1998  [000] d...   140.733510: sys_close(fd: a)
              bash-1998  [000] d...   140.733510: sys_close -> 0x0
              bash-1998  [000] d...   140.733514: sys_rt_sigprocmask(how: 0, nset: 0, oset: 6e2768, sigsetsize: 8)
              bash-1998  [000] d...   140.733515: sys_rt_sigprocmask -> 0x0
              bash-1998  [000] d...   140.733516: sys_rt_sigaction(sig: 2, act: 7fff718846f0, oact: 7fff71884650, sigsetsize: 8)
              bash-1998  [000] d...   140.733516: sys_rt_sigaction -> 0x0

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

Для удаления экземпляров просто удалите соответствующие каталоги

  # rmdir instances/foo
  # rmdir instances/bar
  # rmdir instances/zoot

Отметим, что при наличии у процесса открытого в удаляемом экземпляре файла rmdir будет приводить к отказу с ошибкой EBUSY.

Трассировка стека

Поскольку размер стека ядра фиксирован, важно не исчерпать этот размер вызовами функций. Разработчики ядра должны понимать, что они помещают в стек. Если добавлять туда слишком много, может произойти переполнение стека, которое обычно ведет к аварийному завершению работы системы.

Существуют инструменты, периодически проверяющие использование стека (обычно с прерываниями). Поскольку ftrace обеспечивает трассировку функций, это позволяет проверять размер стека при каждом вызове функции. Это включается через трассировщик стека. Для включения возможности трассировки стека служит конфигурационный параметр ядра CONFIG_STACK_TRACER.

Для включения трассировки стека записывается 1 в файл /proc/sys/kernel/stack_tracer_enabled

 # echo 1 > /proc/sys/kernel/stack_tracer_enabled

Можно также включить трассировку из командной строки ядра для отслеживания стека в процессе загрузки ядра путем добавления команды stacktrace.

Через несколько минут после активизации трассировки можно посмотреть результаты.

  # cat stack_max_size8
  2928
  # cat stack_trace
          Depth    Size   Location    (18 entries)
          -----    ----   --------
    0)     2928     224   update_sd_lb_stats+0xbc/0x4ac
    1)     2704     160   find_busiest_group+0x31/0x1f1
    2)     2544     256   load_balance+0xd9/0x662
    3)     2288      80   idle_balance+0xbb/0x130
    4)     2208     128   __schedule+0x26e/0x5b9
    5)     2080      16   schedule+0x64/0x66
    6)     2064     128   schedule_timeout+0x34/0xe0
    7)     1936     112   wait_for_common+0x97/0xf1
    8)     1824      16   wait_for_completion+0x1d/0x1f
    9)     1808     128   flush_work+0xfe/0x119
   10)     1680      16   tty_flush_to_ldisc+0x1e/0x20
   11)     1664      48   input_available_p+0x1d/0x5c
   12)     1616      48   n_tty_poll+0x6d/0x134
   13)     1568      64   tty_poll+0x64/0x7f
   14)     1504     880   do_select+0x31e/0x511
   15)      624     400   core_sys_select+0x177/0x216
   16)      224      96   sys_select+0x91/0xb9
   17)      128     128   system_call_fastpath+0x16/0x1b

Отметим, что при использовании опции -mfentry в компиляторе gcc функции будут отслеживаться до того, как они организуют кадр стека. Это означает, что функции конечного уровня (листья — leaf) не будут отслеживаться трассировщиком стека при использовании опции -mfentry. В настоящее время эта опция поддерживается gcc 4.6.0 и выше только на архитектуре x86.


По материалам документации к ядру Linux

Николай Малых

nmalykh@protokols.ru

1Следует отметить, что в некоторых вариантах Linux каталог /sys/kernel/tracing остается пустым, а все упомянутые здесь файлы размещаются только в /sys/kernel/debug/tracing

2В GCC термин trampoline означает метод реализации указателей на вложенные функции. Trampoline — это небольшой фрагмент кода, который создается «на лету» в стеке, когда берется адрес вложенной функции. Trampoline устанавливает статический указатель на привязку (link), который позволяет вложенной функции обращаться к переменным вмещающей ее функции. Указателем на функцию является просто адрес trampoline. Это избавляет от применения «толстых» указателей на функции, передающих адрес кода и статическую ссылку. Однако это вступает в противоречие с тенденцией отказа от исполняемого стека по соображениям безопасности.

3Real time.

4Следует отметить, что, не смотря на одиночный символ >, содержимое файла не переписывается и меняется лишь строка указанной опции.

5Thread Group ID — идентификатор группы потоков.

6Включение FTRACE будет добавлять опции -pg при компиляции ядра

7Начиная с gcc версии 4.6 для процессоров x86 можно добавить опцию -mfentry, которая будет вызывать __fentry__ взамен mcount до создания кадра стека.

8Эта команда показывает не максимальный размер стека, а его максимальное использование к текущему моменту. Для просмотра максимального размера стека, установленного в ядре, служит команда ulimit -s.

Рубрика: Linux | Комментарии к записи Трассировщик функций ftrace отключены

Сборка ядра Linux версии 5.2.9 для платформ RISC-V

PDF

Аннотация

Проектирование встраиваемых систем – динамичная область знаний, которая интегрирует аппаратное и программное обеспечение. Со стороны сообщества Linux сделан колоссальный вклад в развитие мира встраиваемых систем в форме свободно распространяемого исходного кода и поддержки различных процессорных архитектур, включая RISCV. Для переноса операционной системы исходный код ядра настраивается, кросс-компилируется и устанавливается на целевую систему. Мы использовали плату HiFive Unleashed, оснащенную множеством периферийных компонентов, которые позволяют создавать комплексные системы, где можно запускать разнообразные приложения. В рамках стоящих перед нами задач нас интересует в первую очередь оценка производительности сетевых операций. Эта статья дает общее представление о технике переноса и разработке приложений для встраиваемых сетевых систем.

Предпосылки и обоснование выбора

Для тестирования производительности сетевых операций на платформе HiFive Unleashed нам требовалась операционная система Linux с ядром, поддерживающим функции трассировки и оценки производительности. Первоначально было предпринято несколько попыток добиться желаемых результатов на основе поддерживаемого компанией SiFive пакета SiFive Freedom Unleashed (FU) SDK [1], включающего несколько ветвей с разными версиями ядра Linux. Однако создать загрузочный образ на основе собранного с использованием [1] ядра и поддерживаемого компанией SiFive демонстрационного образа Debian [2] или образа Fedora RISCV [3], обеспечивающий нужную функциональность и достаточно стабильную работу, не удалось.

В результате был сделан выбор в пользу разрабатываемой компанией SiFive ветви SiFive OpenEmbedded (OE) [4] с поддержкой ядра Linux версии 5.

Сборка подготовленного образа

Ветвь кода SiFive OE построена на основе репозитория repo от Google и существенно отличается от остальной части FU SDK. Строго говоря, это новое направление, связанное с FU SDK лишь общей аппаратной платформой — HiFive Unleashed.

В отличие от FU SDK, здесь не только создаются ядро и компоненты загрузки для платы HiFive Unleashed, но и собирается достаточно функциональный дистрибутив Linux, похожий на Debian.

Рассмотрим сначала создание загрузочных образов с принятыми по умолчанию настройками.

Процесс начинается с установки программы repo, если в вашей системе ее еще нет. Процедура установки и инициализации repo достаточно подробно и внятно описана на странице Google [5], поэтому не будем на этом останавливаться.

После этого нужно создать каталог для дерева исходных кодов, который после загрузки и сборки компонент займет около 80 Гбайт. Далее все ссылки на файлы будут указываться относительно этого каталога (в нашем случае riscvsifive).

$ mkdir riscv-sifive
$ cd riscv-sifive
$ repo init -u git://github.com/sifive/meta-sifive -b master -m tools/manifests/sifive.xml
$ repo sync

Последняя команда может выполняться достаточно долго в зависимости от скорости соединения с сетью и производительности дисковой подсистемы компьютера. Общий объем загруженных файлов составляет приблизительно 300 Мбайт.

Затем вводится команда

$ repo start work --all

для начала работы со всеми ветвями проекта. Следом необходимо настроить среду сборки требуемых образов с помощью команды

$ . ./meta-sifive/setup.sh

Для тех, кто не знает или запамятовал, отметим, что точка в начале строки означает запуск принятого по умолчанию интерпретатора команд (например, bach). После ввода команды на консоль будет выведена достаточно много сообщений, частично проиллюстрированных ниже.

Init OE 
You had no conf/local.conf file. This configuration file has therefore been 
created for you with some default values. You may wish to edit it to, for 
example, select a different MACHINE (target hardware). See conf/local.conf 
for more information as common configuration options are commented. 

You had no conf/bblayers.conf file. This configuration file has therefore been 
created for you with some default values. To add additional metadata layers 
into your configuration please add entries to conf/bblayers.conf. 

The Yocto Project has extensive documentation about OE including a reference 
manual which can be found at: 
   http://yoctoproject.org/documentation 

For more information about OpenEmbedded see their website: 
   http://www.openembedded.org/ 


### Shell environment set up for builds. ### 

You can now run 'bitbake <target>' 

Common targets are: 
   core-image-minimal 
   core-image-sato 
   meta-toolchain 
   meta-ide-support 

You can also run generated qemu images with a command like 'runqemu qemux86' 
Adding layers 
NOTE: Starting bitbake server... 
... 

NOTE: Starting bitbake server... 
Creating auto.conf 
--------------------------------------------------- 
MACHINE=freedom-u540 bitbake demo-coreip-cli 
--------------------------------------------------- 

Buildable machine info 
--------------------------------------------------- 
* freedom-u540: The SiFive HiFive Unleased board 
* qemuriscv64: The 64-bit RISC-V machine 
---------------------------------------------------

На этом этапе система готова к сборке загрузочного образа с принятыми по умолчанию параметрами. Для начала сборки следует ввести в консоли команду, приведенную в конце показанного выше вывода

$ MACHINE=freedom-u540 bitbake demo-coreip-cli

Эта команда указывает тип машины, для которой выполняется сборка (freedomu540) и образ (democoreipcli), собираемый с помощью команды bitbake. После запуска команды начнется весьма долгий процесс загрузки ядра и требуемых пакетов, их настройки и сборки.

Initialising tasks: 100% |################################################################| Time: 0:00:18 
Parsing of 2389 .bb files complete (0 cached, 2389 parsed). 3490 targets, 134 skipped, 0 masked, 0 errors. 
NOTE: Resolving any missing task queue dependencies 

Build Configuration: 
BB_VERSION           = "1.43.1" 
BUILD_SYS            = "x86_64-linux" 
NATIVELSBSTRING      = "mageia-7" 
TARGET_SYS           = "riscv64-oe-linux" 
MACHINE              = "freedom-u540" 
DISTRO               = "nodistro" 
DISTRO_VERSION       = "nodistro.0" 
TUNE_FEATURES        = "riscv64 littleendian" 
meta                 = "work:6b36db836547a23f43c5f97bf3706d7b210c209c" 
meta-oe               
meta-python           
meta-multimedia       
meta-networking       
meta-gnome            
meta-xfce            = "work:4e0538516b1e0ef42dc79bd08f7895f0052063ac" 
meta-riscv           = "work:99cdf8d0cfe4b515ccac76c816091b146d0a012b" 
meta-sifive          = "work:87a209be777318fefb87da6e295f4c34540717f3" 

NOTE: Fetching uninative binary shim from http://downloads.yoctoproject.org/releases/uninative/2.6/x86_64-nativesdk-libc.tar.xz;sha256sum=133387753a9acf3e1b788103c59fac91e968e2ee331d7a4b9498e926ada7be57 
Initialising tasks: 100% |################################################################| Time: 0:00:04 
Sstate summary: Wanted 1950 Found 0 Missed 1950 Current 0 (0% match, 0% complete) 
NOTE: Executing Tasks 
NOTE: Setscene tasks completed
...

Следует отметить, что в процессе первоначальной настройки с большой вероятностью возникнут те или иные проблемы и процесс завершится ошибкой. В таком случае следует внимательно просмотреть содержимое вывода на консоль и log-файлы. Обычно, при возникновении ошибки, программа выводит на консоль имя файла, в который были записаны сообщения. Анализ вывода позволяет обнаружить недостающие или некорректно настроенные компоненты системы и устраните неполадки. Пример сообщения о создании журнала ошибок приведен ниже:

ERROR: Logfile of failure stored in: riscv-sifive/build/tmp-glibc/work/x86_64-linux/shared-mime-info-native/1.10-r0/temp/log.do_compile.39743

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

riscv-sifive/build/tmp-glibc/work/x86_64-linux/shared-mime-info-native/1.10-r0/build/freedesktop.org.xml

Решить проблему после ее обнаружения удалось путем копирования в упомянутый каталог файла /usr/share/mime/packages/freedesktop.org.xml. Другая проблема была связана со сборкой пакета networkmanager и решить ее удалось только “вручную”, путем сборки части пакета вне процесса bitbake после анализа вывода программы и обнаружения точки возникновения ошибки.

Процесс сборки занимает достаточно продолжительное время (на системе x86 с 40 ядрами и гигабитным каналом доступа в Internet процесс тянулся более часа). В конце концов после некоторого ожидания и правки ошибок будет выведено сообщение вида

...
NOTE: Tasks Summary: Attempted 5681 tasks of which 5423 didn't need to be rerun and all succeeded. 
NOTE: Writing buildhistory 
NOTE: Writing buildhistory took: 1 seconds 
NOTE: Build completion summary: 
NOTE:   do_populate_sysroot: 0.0% sstate reuse(0 setscene, 6 scratch) 
NOTE:   do_package_qa: 0.0% sstate reuse(0 setscene, 8 scratch) 
NOTE:   do_package: 0.0% sstate reuse(0 setscene, 7 scratch) 
NOTE:   do_packagedata: 0.0% sstate reuse(0 setscene, 7 scratch) 
NOTE:   do_package_write_ipk: 0.0% sstate reuse(0 setscene, 8 scratch) 
NOTE:   do_populate_lic: 0.0% sstate reuse(0 setscene, 2 scratch) 

Summary: There was 1 WARNING message shown.

Это означает, что процедура установки, настройки и сборки компонент завершилась без ошибок и полученный образ можно копировать на карту микро-SD для загрузки платы HiFive Unleashed. Подготовленные образы для установки на карту микро-SD будут размещаться в каталоге riscvsifive/build/tmpglibc/deploy/images/freedomu540.Процесс сборки завершается в каталоге riscvsifive/build.
Для переноса образов на карту микро-SD необходимо выполнить команды

$ cd  ./tmp-glibc/deploy/images/freedom-u540 $ zcat demo-coreip-cli-freedom-u540.wic.gz | sudo dd of=/dev/sdX bs=512K iflag=fullblock oflag=direct conv=fsync status=progress

где вместо sdX нужно указать имя реального устройства, с которым ваша система видит подключенную к ней карту микро-SD. В нашем случае карта имела в системе имя sdk, которое дальше и будет указываться. Для установки образов достаточно карты размером 8 Гбайт. Если вы возьмете карту большего размера, на ней все равно будут созданы разделы таких размеров, как будто использовалась карта на 8 Гбайт. При желании можно после копирования изменить размер корневого раздела с помощью gparted или иной подходящей программы.

$ zcat demo-coreip-cli-freedom-u540.wic.gz | sudo dd of=/dev/sdk bs=512K iflag=fullblock oflag=direct conv=fsync status=progress [sudo] пароль для user:  
7124549632 байт (7,1 GB, 6,6 GiB) скопирован, 523 s, 13,6 MB/s 
13600+1 записей получено 
13600+1 записей отправлено 
7130334208 байт (7,1 GB, 6,6 GiB) скопирован, 523,467 s, 13,6 MB/s

Отключаем карту микро-SD от сборочного компьютера, переносим ее в гнездо платы HiFive Unleashed и включаем питание платы. Для наблюдения за процессом использовалась консоль программы screen, запущенной на отладочной машине, которая соединена с платой кабелем USB. Вывод консоли начала процесса загрузки платы HiFive Unleashed с созданным образом частично показан ниже.

$ zcat demo-coreip-cli-freedom-u540.wic.gz | sudo dd of=/dev/sdk bs=512K iflag=fullblock oflag=direct conv=fsync status=progress [sudo] пароль для user:  
7124549632 байт (7,1 GB, 6,6 GiB) скопирован, 523 s, 13,6 MB/s 
13600+1 записей получено 
13600+1 записей отправлено 
7130334208 байт (7,1 GB, 6,6 GiB) скопирован, 523,467 s, 13,6 MB/s

Отключаем карту микро-SD от сборочного компьютера, переносим ее в гнездо платы HiFive Unleashed и включаем питание платы. Для наблюдения за процессом использовалась консоль программы screen, запущенной на отладочной машине, которая соединена с платой кабелем USB. Вывод консоли начала процесса загрузки платы HiFive Unleashed с созданным образом частично показан ниже.

$ zcat demo-coreip-cli-freedom-u540.wic.gz | sudo dd of=/dev/sdk bs=512K iflag=fullblock oflag=direct conv=fsync status=progress
[sudo] пароль для user:  
7124549632 байт (7,1 GB, 6,6 GiB) скопирован, 523 s, 13,6 MB/s 
13600+1 записей получено 
13600+1 записей отправлено 
7130334208 байт (7,1 GB, 6,6 GiB) скопирован, 523,467 s, 13,6 MB/s

Отключаем карту микро-SD от сборочного компьютера, переносим ее в гнездо платы HiFive Unleashed и включаем питание платы. Для наблюдения за процессом использовалась консоль программы screen, запущенной на отладочной машине, которая соединена с платой кабелем USB. Вывод консоли начала процесса загрузки платы HiFive Unleashed с созданным образом частично показан ниже.

SiFive FSBL:       2019-09-18-128f282-dirty
Using FSBL DTB
HiFive-U serial #: 00000220
Loading boot payload........


OpenSBI v0.4-21-ga2a7763 (Sep 18 2019 16:39:38)
   ____                    _____ ____ _____
  / __ \                  / ____|  _ \_   _|
 | |  | |_ __   ___ _ __ | (___ | |_) || |
 | |  | | '_ \ / _ \ '_ \ \___ \|  _ < | |
 | |__| | |_) |  __/ | | |____) | |_) || |_
  \____/| .__/ \___|_| |_|_____/|____/_____|
        | |
        |_|

Platform Name          : SiFive Freedom U540
Platform HART Features : RV64ACDFIMSU
Platform Max HARTs     : 5
Current Hart           : 1
Firmware Base          : 0x80000000
Firmware Size          : 100 KB
Runtime SBI Version    : 0.1

PMP0: 0x0000000080000000-0x000000008001ffff (A)
PMP1: 0x0000000000000000-0x0000007fffffffff (A,R,W,X)


U-Boot 2019.07 (Sep 18 2019 - 16:32:19 +0000)

CPU:   rv64imafdc
Model: SiFive HiFive Unleashed A00
DRAM:  8 GiB
MMC:   spi@10050000:mmc@0: 0
In:    serial@10010000
Out:   serial@10010000
Err:   serial@10010000
Net:   eth0: ethernet@10090000
Hit any key to stop autoboot:  2 ### 1 ### 0
switch to partitions #0, OK
mmc0 is current device
Scanning mmc 0:1...
Found U-Boot script /boot.scr.uimg
678 bytes read in 3 ms (220.7 KiB/s)
## Executing script at 88100000
9326152 bytes read in 4707 ms (1.9 MiB/s)
## Loading kernel from FIT Image at 88300000 ...
   Using 'conf@sifive_hifive-unleashed-a00-microsemi.dtb' configuration
   Trying 'kernel@1' kernel subimage
     Description:  Linux kernel
     Type:         Kernel Image
     Compression:  gzip compressed
     Data Start:   0x883000fc
     Data Size:    9317433 Bytes = 8.9 MiB
     Architecture: RISC-V
     OS:           Linux
     Load Address: 0x80200000
     Entry Point:  0x80200000
     Hash algo:    sha256
     Hash value:   62f8986a3de46f822f9c75388982836bf6f43c4de9a5cf63d4288c7454f51dc0
   Verifying Hash Integrity ... sha256+ OK
## Loading fdt from FIT Image at 88300000 ...
   Using 'conf@sifive_hifive-unleashed-a00-microsemi.dtb' configuration
   Trying 'fdt@sifive_hifive-unleashed-a00-microsemi.dtb' fdt subimage
     Description:  Flattened Device Tree blob
     Type:         Flat Device Tree
     Compression:  uncompressed
     Data Start:   0x88be2e64
     Data Size:    6677 Bytes = 6.5 KiB
     Architecture: RISC-V
     Load Address: 0x82200000
     Hash algo:    sha256
     Hash value:   b704ade210b1ac4161e2abb16a5e0e1a437aae731b9b49e7b5c41f357e4a8e4e
   Verifying Hash Integrity ... sha256+ OK
   Loading fdt from 0x88be2e64 to 0x82200000
   Booting using the fdt blob at 0x82200000
   Uncompressing Kernel Image ... OK
   Using Device Tree in place at 0000000082200000, end 0000000082204a14

Starting kernel ...

Уже самое начало процесса загрузки показывает, что он организован иначе, нежели в образах FU SDK — вместо загрузчика BBL [6, 7] используется OpenSBI [8, 9]. Не будем сейчас вдаваться в детали, а лишь отметим, что загрузка системы в этом варианте во много раз быстрей по сравнению с FU SDK на основе BBL.

По умолчанию для входа в систему служит имя пользователя root с пустым паролем (Enter). Изучением полученной системы каждый может заняться самостоятельно, а мы рассмотрим некоторые вопросы настройки создаваемого образа.

Настройка параметров ядра и компонент системы

Настройка параметров и компонент образа описана достаточно подробно в документах [10 — 12]. Система имеет также графический Web-интерфейс Toaster [13] для настройки компонент собираемого образа. Желающие могут изучить в деталях варианты настроек самостоятельно по приведенным в конце ссылкам. Нам же нужно изменить конфигурацию ядра Linux и добавить некоторое число пакетов в образ, что можно сделать вручную, просто редактируя нужные файлы.

Параметры конфигурации ядра определяются файлом riscv-sifive/build/tmp-glibc/work/freedom_u540-oe-linux/linux-mainline/5.2.9+gitAUTOINC+aad39e30fb-r0/linux-freedom_u540-standard-build/.config. Этот файл создается или обновляется в процессе сборки образов на основе файла riscv-sifive/meta-sifive/recipes-kernel/linux/files/freedom-u540/defconfig, содержащего набор конфигурационных параметров ядра, а также других фрагментов конфигурации, размещенный в многочисленных файлах. Файл defconfig достаточно безопасно можно редактировать вручную, если вы представляете смысл и назначение изменяемых параметров. Однако следует отметить, что при создании итоговой конфигурации ядра файл defconfig анализируется в самом начале процесса и некоторые опции, заданные в нем могут быть переопределены другими фрагментами конфигурации.

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

CONFIG_LATENCYTOP=y 
CONFIG_NOP_TRACER=y 
CONFIG_HAVE_FUNCTION_TRACER=y 
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y 
CONFIG_HAVE_DYNAMIC_FTRACE=y 
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y 
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y 
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y 
CONFIG_TRACER_MAX_TRACE=y 
CONFIG_TRACE_CLOCK=y 
CONFIG_RING_BUFFER=y 
CONFIG_EVENT_TRACING=y 
CONFIG_CONTEXT_SWITCH_TRACER=y 
CONFIG_RING_BUFFER_ALLOW_SWAP=y 
CONFIG_PREEMPTIRQ_TRACEPOINTS=y 
CONFIG_TRACING=y 
CONFIG_GENERIC_TRACER=y 
CONFIG_TRACING_SUPPORT=y 
CONFIG_FTRACE=y 
CONFIG_FUNCTION_TRACER=y 
CONFIG_FUNCTION_GRAPH_TRACER=y 
CONFIG_PREEMPTIRQ_EVENTS=y 
CONFIG_IRQSOFF_TRACER=y 
CONFIG_SCHED_TRACER=y 
CONFIG_HWLAT_TRACER=y 
CONFIG_FTRACE_SYSCALLS=y 
CONFIG_TRACER_SNAPSHOT=y 
CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP=y 
CONFIG_TRACE_BRANCH_PROFILING=y 
CONFIG_PROFILE_ALL_BRANCHES=y 
CONFIG_STACK_TRACER=y 
CONFIG_DYNAMIC_FTRACE=y 
CONFIG_DYNAMIC_FTRACE_WITH_REGS=y 
CONFIG_FUNCTION_PROFILER=y 
CONFIG_FTRACE_MCOUNT_RECORD=y 
CONFIG_TRACEPOINT_BENCHMARK=y 
CONFIG_PREEMPTIRQ_DELAY_TEST=m

Если редактировать файл вручную вы не рискнете или результаты такого редактирования не устроят (нужные опции будут переопределены в других файлах), можно воспользоваться инструментами devtool, подробно описанными в [12] (параграф 15.3.3 и далее). Поскольку детали процесса в нашем случае несколько отличаются и не вполне очевидны, ниже приведен список команд, которые позволят активизировать на сборочном хосте пакет интерактивной настройки ядра menuconfig.

Из каталога сборки (build) запускаем команду для создания стартового файла конфигурации ядра (.config).

bitbake linux-mainline -c kernel_configme -f

Если вы уже собирали образ с принятыми по умолчанию настройками, файл конфигурации ядра .config уже имеется в дереве исходных кодов и команду можно опустить, но в любом случае ее запуск не нанесет никакого урона. Далее из того же каталога вводим команду

bitbake linux-mainline -c menuconfig

На экране появится новое консольное окно linux-mainline Configuration с выводом процесса запуска команды make menuconfig, используемой ядром Linux для интерактивной настройки конфигурации, а затем в этом окне будет выведен текстовый интерфейс menuconfig.

 
Процесс редактирования параметров конфигурации ничем не отличается от обычной настройки конфигурации ядра Linux [14] и мы не будем здесь останавливаться. После выбора нужных опций не забудьте сохранить результаты.

После редактирования конфигурации ядра следует расширить набор включаемых в образ операционной системы пакетов и утилит в соответствии с вашими потребностями. Компоненты добавляются с помощью переменной CORE_IMAGE_EXTRA_INSTALL += в файле build/conf/local.conf. Полный список доступных пакетов, отсортированных по алфавиту, можно получить с помощью команды bitbake -s. При добавлении нужных вам пакетов можно не задумываться над зависимостями, они будут проверены автоматически с добавлением нужных пакетов без вашего участия. Добавленные в нашем случае приложения показаны ниже.

CORE_IMAGE_EXTRA_INSTALL += "apt numactl ptpd hwloc netperf man tzdata bootchart \ 
                            swig cmake jsoncpp tcpdump"

После выполнения описанных выше операций нужно повторить сборку ядра и пакетов ОС, а также копирование полученных образов на карту микро-SD.

$ MACHINE=freedom-u540 bitbake demo-coreip-cli
…
$ cd  ./tmp-glibc/deploy/images/freedom-u540 $ zcat demo-coreip-cli-freedom-u540.wic.gz | sudo dd of=/dev/sdk bs=512K iflag=fullblock oflag=direct conv=fsync status=progress

Работу с полученным образом для трассировки и оценки производительности рассмотрим в следующей публикации.

Заключение

В этой статье были рассмотрены некоторые детали настройки конфигурации ядра и всего процесса разработки с RISC-V и встроенным Linux перед запуском реального приложения. В дальнейшем мы сможем добавлять и проектировать периферийные устройства и разрабатывать соответствующие драйверы для Linux, совместимые с RISC-V платой HiFive Unleashed.

Литература

[1] SiFive Freedom Unleashed SDK, https://github.com/sifive/freedom-u-sdk.

[2] HiFive U RiscV-pc alpha release, https://github.com/tmagik/freedom-u-sdk/releases/download/hifiveu-2.0-alpha.1/.

[3] Architectures/RISC-V/Installing, https://dl.fedoraproject.org/pub/alt/risc-v/disk-images/fedora/rawhide/20190703.n.0/Developer/Fedora-Developer-Rawhide-20190703.n.0-sda.raw.xz.

[4] SiFive OpenEmbedded Layer, https://github.com/sifive/meta-sifive.

[5] Installing Repo, https://source.android.com/setup/build/downloading#installing-repo.

[6] All Aboard, Part 6: Booting a RISC-V Linux Kernel, https://www.sifive.com/blog/all-aboard-part-6-booting-a-risc-v-linux-kernel.

[7] RISC-V Proxy Kernel and Boot Loader, https://github.com/riscv/riscv-pk.

[8] RISC-V Open Source Supervisor Binary Interface (OpenSBI), https://github.com/riscv/opensbi

[9] RISC-V Supervisor Binary Interface Specification, https://github.com/riscv/riscv-sbi-doc/blob/master/riscv-sbi.adoc.

[10] BitBake User Manual, https://www.yoctoproject.org/docs/2.7.1/bitbake-user-manual/bitbake-user-manual.html (перевод).

[11] A practical guide to BitBake, https://a4z.bitbucket.io/docs/BitBake/guide.html.

[12] Yocto Project Reference Manual, https://www.yoctoproject.org/docs/2.7.1/ref-manual/ref-manual.html#devtool-modifying-a-recipe (перевод).

[13] Toaster User Manual, https://www.yoctoproject.org/docs/2.7.1/toaster-manual/toaster-manual.html.

[14] Menuconfig, https://en.wikipedia.org/wiki/Menuconfig.

Николай Малых

nmalykh@protokols.ru

Рубрика: Linux, RISC-V | Комментарии к записи Сборка ядра Linux версии 5.2.9 для платформ RISC-V отключены

RFC 8655 Deterministic Networking Architecture

Internet Engineering Task Force (IETF)                           N. Finn
Request for Comments: 8655                                        Huawei
Category: Standards Track                                     P. Thubert
ISSN: 2070-1721                                                    Cisco
                                                                B. Varga
                                                               J. Farkas
                                                                Ericsson
                                                            October 2019

Deterministic Networking Architecture

Архитектура детерминированых сетей

PDF

Аннотация

В этом документе описана базовая архитектура детерминированных сетей (DetNet1), обеспечивающая возможность передачи конкретного группового и индивидуального трафика приложений, работающих в реальном масштабе времени, с минимальными потерями и ограниченной задержкой внутри сетевого домена. Используемые методы включают 1) резервирование ресурсов плоскости данных для индивидуальных (или агрегированных) потоков DetNet на некоторых или всех промежуточных узлах пути, 2) обеспечение явных маршрутов для потоков, которые не меняются сразу при изменении топологии сети, и 3) распределение данных из пакетов потока DetNet во времени и/или пространстве для обеспечения доставки каждого пакета, несмотря на потери в пути. DetNet работает на уровне IP и предоставляет услуги на основе технологий нижележащих уровней, таких как MPLS и TSN2 (IEEE 802.1).

Статус документа

Документ относится к категории Internet Standards Track.

Документ является результатом работы IETF3 и представляет согласованный взгляд сообщества IETF. Документ прошел открытое обсуждение и был одобрен для публикации IESG4. Дополнительную информацию о стандартах Internet можно найти в разделе 2 в RFC 7841.

Информацию о текущем статусе документа, ошибках и способах обратной связи можно найти по ссылке https://www.rfc-editor.org/info/rfc8655.

Авторские права

Авторские права (Copyright (c) 2019) принадлежат IETF Trust и лицам, указанным в качестве авторов документа. Все права защищены.

К документу применимы права и ограничения, указанные в BCP 78 и IETF Trust Legal Provisions и относящиеся к документам IETF (http://trustee.ietf.org/license-info), на момент публикации данного документа. Прочтите упомянутые документы внимательно. Фрагменты программного кода, включённые в этот документ, распространяются в соответствии с упрощённой лицензией BSD, как указано в параграфе 4.e документа IETF Trust Legal Provisions, без каких-либо гарантий (как указано в Simplified BSD License).

1. Введение

В документе представлена архитектура детерминированных сетей DetNet, которая обеспечивает возможность доставки потоков данных с очень низкими потерями пакетов и ограниченной сквозной задержкой. Архитектура DetNet предназначена для сетей с единым администрированием или управляемых тесно связанными администраторами, включая кампусные сети и частные сети WAN. DetNet не рассчитана на большие группы доменов, такие как Internet.

DetNet работает на уровне IP и обеспечивает услуги на основе технологий нижележащих уровней, таких как MPLS и IEEE 802.1 TSN. DetNet обеспечивает надежные и доступные услуги путем выделения сетевых ресурсов (таких как пропускная способность каналов и буферное пространство) для потоков DetNet и/или классов потоков, а также репликации пакетов в несколько путей. Не занятые резервы ресурсов доступны для прочего (не DetNet) трафика, если гарантии соблюдены.

Документ Deterministic Networking Problem Statement [RFC8557] является введением в DetNet, а в Deterministic Networking Use Cases [RFC8578] обоснована потребность в архитектуре. Конкретные методы идентификации потоков DetNet и назначения им определенных путей через сеть рассмотрены в [DETNET-FRAMEWORK].

Целью DetNet является создание конвергентных сетей, включая объединение критичных сетей без протокола IP в общую сетевую инфраструктуру. Присутствие потоков DetNet не мешает другим потокам, а преимущества потоков DetNet в большинстве случаев не должны препятствовать нормальной работе имеющихся механизмов QoS5 если для потоков DetNet достаточно пропускной способности. Для данной пары отправитель-получатель могут поддерживаться одновременно DetNet и иные потоки. Конечным системам и приложениям не требуются специальные интерфейсы для потоков DetNet. Сети не привязаны к определенной топологии и типы подключений не ограничиваются. Любое приложение, создающее поток данных, который можно охарактерировать как занимающий ограниченную пропускную способность, должно иметь возможность использовать преимущества DetNet при условии резервирования требуемых ресурсов. Резервирование может организовать само приложение через управление сетью или централизованный контроллер приложений, а также иные средства, например, это можно сделать путем резервирования по запросу через распределенную плоскость управления по протоколу RSVP6 [RFC2205]. Требования QoS для потоков DetNet могут быть выполнены, если все узлы сети в домене DetNet поддерживают возможности DetNet. Узлы DetNet могут соединяться с использованием разных технологий (4.1.2. Обзор плоскости данных DetNet), при этом узлы подсетей могут не знать о DetNet (4.1.3. Модель эталонной сети).

Многим приложениям, рассчитанным на услуги DetNet, нужна возможность синхронизировать часы оконечных систем с микросекундной точностью. Некоторые методы управления очередями, определенные в разделе 4.5. Очереди, формирование, планирование и вытеснение трафика, также требуют синхронизации между узлами сети. Средства обеспечения такой синхронизации в этом документе не рассматриваются. DetNet может использовать разные методы синхронизации часов, определенные в других документах, для решения своих задач, диктуемых рынком.

2. Терминология

2.1. Используемые в документе термины

Ниже приведены определения терминов, используемых в этом документе.

allocation — выделение

Выделение ресурсов для поддержки потока DetNet. В зависимости от реализации ресурс может отдаваться за пределы DetNet, когда он не нужен потоку DetNet.

App-flow — поток приложения

Данные (payload), передаваемые через службы DetNet.

DetNet compound flow и DetNet member flow — составной поток DetNet и поток участника DetNet

Составным потоком DetNet называется поток DetNet, разделенный на несколько дубликатов потоков членов DetNet для защиты на подуровне сервиса DetNet. Потоки членов объединяются в один составной поток DetNet без дублирования пакетов. Понятия «составной поток» и «поток участника» не являются абсолютными. Составной поток DetNet, содержащий множество потоков членов DetNet, может быть включен в составной поток более высокого уровня.

DetNet destination — получатель DetNet

Конечная система, способная завершать поток DetNet.

DetNet domain — домен DetNet

Часть сети, поддерживающая DetNet. Включает конечные системы и узлы DetNet.

DetNet edge node — краевой узел DetNet

Экземпляр ретранслятора DetNet, выступающий в качестве источника и получателя на подуровне службы DetNet. Например, он может включать функцию посредника подуровня DetNet для защиты сервиса DetNet (добавление и удаление данных упорядочения пакетов) одной или множества конечных систем, начинать или завершать выделение ресурсов на подуровне пересылки DetNet в новых потоках DetNet. Такой узел аналогичен маршрутизатору LER7 или PE8.

DetNet flow — поток DetNet

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

DetNet forwarding sub-layer — подуровень пересылки DetNet

Функциональность DetNet разделена на два подуровня. Одним из них является подуровень пересылки DetNet, который может также обеспечивать выделение ресурсов для потоков DetNet на путях через базовую сеть.

DetNet intermediate node — промежуточный узел DetNet

Ретранслятор или промежуточный узел DetNet.

DetNet node — узел DetNet

Краевой узел, ретранслятор или промежуточный узел DetNet.

DetNet relay node — ретранслятор DetNet

Узел DetNet, включающий функцию подуровня сервиса, которая соединяет разные пути пересылки DetNet для обеспечения защиты сервиса. Ретранслятор DetNet участвует в работе сервисного подуровня DetNet. Обычно он также включает функции подуровня пересылки DetNet и в этом случае совмещается с транзитным узлом.

DetNet service sub-layer — сервисный подуровень DetNet

Функциональность DetNet разделена на два подуровня. Одним из них является сервисный подуровень DetNet, обеспечивающий услуги DetNet (например, защиту сервиса).

DetNet service proxy — прокси службы DetNet

Посредник, обеспечивающий отображение между потоками приложений и потоками DetNet.

DetNet source — источник DetNet

Конечная система, способная создавать поток DetNet.

DetNet system — система DetNet (система)

Поддерживающая DetNet конечная система, промежуточный узел или ретранслятор.

DetNet transit node — транзитный узел DetNet

Узел DetNet, работающий на подуровне пересылки DetNet и использующий коммутацию канального и/или сетевого уровня между несколькими каналами и/или подсетями для обеспечения путей сервисного подуровня DetNet. Обычно такой узел обеспечивает выделение ресурсов для этих путей. Примером транзитного узла является LSR9.

DetNet-UNI

Интерфейс пользователь-сеть (User-to-Network Interface — UNI) с функциональностью DetNet. Это опорная точка на уровне пакетов, способная выполнять функции инкапсуляции, синхронизации, поддержки состояния и т. п.

end system — конечная система

Обычно называется хостом в документах RFC и конечной станцией в стандартах IEEE 802. В этом документе рассматриваются конечные системы, являющиеся отправителями или получателями потоков DetNet, которые могут (но не обязаны) поддерживать подуровни сервиса и пересылки DetNet.

link

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

Packet Elimination Function (PEF) — функция исключения дубликатов

Функция, исключающая дублирование копий пакетов, для предотвращения лавинной пересылки пакетов в сеть или дублирования пакетов, выходящих из домена DetNet. PEF может быть реализована на граничном узле, ретрансляторе или конечной системе DetNet.

Packet Replication Function (PRF) — функция репликации пакетов

Функция, реплицирующая пакеты потоков DetNet и пересылающая их на один или несколько следующих интервалов домена DetNet. Число пакетов, передаваемых на следующий интервал, является параметром потока DetNet в точке репликации. PRF можно реализовать на граничном узле, ретрансляторе или конечной системе.

PREOF

Общее название функций репликации, исключения дубликатов и упорядочения.

Packet Ordering Function (POF) — функция упорядочения пакетов

Функция восстановления порядка пакетов в потоке DetNet, которая может быть реализована на граничном узле, ретрансляторе или конечной системе DetNet.

reservation — резервирование

Набор ресурсов, выделяемых отправителю и одному или множеству получателей на узлах и подсетях, связанных с потоком DetNet, для обеспечения сервиса DetNet.

2.2. Термины, используемые TSN и DetNet

Этот параграф служит словарем для перевода терминов, применяемых группой TSN [IEEE802.1TSNTG] в составе IEEE 802.1 WG, в термины рабочей группы WG в рамках IETF.

Listener — слушатель

Термин, используемый в IEEE 802.1, для получателей потоков DetNet.

Relay system — ретранслятор

Термин, используемый в IEEE 802.1, для промежуточных узлов DetNet.

Stream — поток

Термин, используемый в IEEE 802.1, для потоков DetNet.

Talker — “оратор”

Термин, используемый в IEEE 802.1, для источников потоков DetNet.

3. Обеспечение качества обслуживания в DetNet

3.1. Основные цели определения DetNet QoS

DetNet QoS можно выразить несколькими способами, указанными ниже.

  • Минимальная и максимальная сквозная задержка между отправителем и получателем, своевременная доставка и ограниченные вариации задержки.

  • Доля теряемых пакетов в разных условиях, связанных с рабочими состояниями узлов и каналов.

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

Отличительной чертой DetNet является работа исключительно с худшими вариантами сквозной задержки, ее вариаций и нарушения порядка доставки. Нормальные, усредненные и типовые значения малоинтересны, поскольку они не влияют на способность систем выполнять свои задачи в реальном масштабе времени. В общем случае тривиальная система управления очередями по приоритетам будет давать для потока данных лучшую среднюю задержку, нежели DetNet, однако она не подходит для DetNet при учете наибольшей задержки.

В DetNet используются три метода обеспечения качества обслуживания:

  • 3.2.1. Выделение ресурсов;

  • 3.2.2. Защита сервиса;

  • 3.2.3. Явные маршруты.

Выделение ресурсов происходит путем назначения ресурса (например, буферной емкости или пропускной способности канала) потоку или группе потоков DetNet по пути их следования. Выделение ресурсов существенно снижает или даже исключает потерю пакетов в результате конфликтов при передаче пакетов в сети, но применимо лишь к потоку DetNet, ограниченному у отправителя по размеру пакетов и скорости их передачи. Поскольку предполагается ограничение скорости потоков DetNet и предоставление в DetNet достаточных ресурсов (включая пропускную способность), применять контроль перегрузок на транспортном уровне [RFC2914] для потоков приложений (App-flow) не требуется, однако при подобающем выделении ресурсов контроль перегрузок не будет оказывать негативного влияния.

Выделение ресурсов выполняет требования DetNet QoS по задержке и потере пакетов. С учетом ограниченности буферов на узлах DetNet выделение ресурсов обязательно влияет на максимальную сквозную задержку. Выделение ресурсов также решает проблему потери пакетов, связанной с конкуренцией.

Другим важным вкладом в потерю пакетов являются случайные ошибки в среде и сбои в оборудовании. Защитой сервиса называются механизмы, используемые в DetNet для устранения таких потерь. Применяемые механизмы ограничены необходимостью выполнять требования пользователей к задержкам. В параграфах 3.2.2.2. Репликация и устранение копий и 3.2.2.3. Кодирование пакетов для защиты сервиса описаны два метода защиты сервиса, но могут применяться и другие механизмы. Например, может использоваться кодирование пакетов для защиты сервиса от случайных ошибок в среде, а репликация и устранение копий — для защиты от сбоев оборудования. Этот механизм распределяют потоки DetNet по нескольким путям в пространстве и/или времени, поэтому потеря некоторых путей не обязательно приведет к потере каких-либо пакетов.

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

Эти три метода могут применяться по отдельности или совместно. Возможно использование любой комбинации, включая полное отсутствие (без DetNet). Однако некоторые сочетания используются чаще. Такое разделение обеспечивает согласованность стека протоколов и максимальную совместимость с имеющимися и разрабатываемыми стандартами (в IETF и других организациях). Ниже приведено несколько примеров типовых сочетаний.

  • Комбинация явных маршрутов и защиты сервиса является методом организации бесшовной избыточности в кольцевой топологии, как описано в [IEC-62439-3]. В этом случае явные маршруты обеспечиваются за счет ограничения физической топологии сети кольцом. Упорядочение, репликация и устранение дубликатов обеспечиваются добавлением тегов в начале или в конце кадров Ethernet. В [RFC8227] представлен другой пример в контексте MPLS.

  • Выделение ресурсов в качестве единственного метода было предложено в IEEE 802.1 Audio Video Bridging [IEEE802.1BA]. Пока в сети не возникает отказов, потеря пакетов в результате конкуренции на выходе может быть устранена с помощью протокола резервирования (например, Multiple Stream Registration Protocol [IEEE802.1Q]), формирователей в каждом мосту и соблюдения нужных размеров.

  • Использование всех трех методов обеспечивает максимальную защиту.

Имеются и другие доступные (и развернутые) методы обеспечения приемлемой задержки и потери пакетов для многих приложений. К таким методам относится приоритизация и предоставление избыточных ресурсов (over-provisioning). Однако такие методы лучше всего работают при отсутствии в сети значимого объема некритичного трафика (если такой трафик поддерживается). Они могут работать лишь в тех случаях, когда критичный к задержкам и потерям трафик составляет малую часть от теоретической пропускной способности сети, все системы работают корректно и нет конечных систем, действия которых нарушают работу сети.

Определено, применяется или разрабатывается много механизмов реализации каждого из отмеченных выше методов. Предполагается, что определенная здесь архитектура DetNet поможет производителям, пользователям и «вертикальным» органам стандартизации (отраслевым) сделать выбор между доступными реализациями сетей DetNet.

3.2. Механизмы обеспечения DetNet QoS

3.2.1. Выделение ресурсов

3.2.1.1. Устранение потерь в результате конкуренции

Основным способом достижения гарантий QoS в DetNet является снижение или даже полное устранение потери пакетов в результате конкуренции в выходных очередях на узлах DetNet. Это можно реализовать лишь обеспечением достаточного объема буферов, чтобы пакеты не терялись в результате нехватки буферной емкости. Отметим, что в общем случае не предполагается реакция потоков приложений на неявные [RFC2914] или явные [RFC3168] уведомления о перегрузке.

Обеспечение адекватной буферизации требует от отправителя и каждого узла в пути DetNet к получателю (почти каждый узел, см. параграф 4.3.3) аккуратного регулирования своего вывода, чтобы не превышалась скорость для каждого потока DetNet за исключением кратких периодов сочетания с мешающим трафиком. Любой пакет, отправленный раньше времени, может добавлять объем буферов, требуемых на следующем узле DetNet, что может приводить к выходу за пределы выделенных отдельному потоку DetNet ресурсов. Кроме того, на входе в домен DetNet должны применяться функции ограничения скорости (например, правила для трафика) и механизмы формовки (например, [RFC2475]). Это нужно для соблюдения требований DetNet, а также для защиты остального (не DetNet) трафика от некорректно работающих источников трафика DetNet. Отметим, что большие буферы создают некоторые проблемы (см. например, [BUFFERBLOAT]).

Описанные в параграфе 4.5 механизмы нижних уровней обеспечивают требуемое регулирование передачи в конечных системах или узлах DetNet с учетом выделения ресурсов. Выделенную для потока DetNet пропускную способность или буферы требуется обеспечить. Узел DetNet может иметь другие ресурсы, требующие выделения и/или планирования, которые могут быть без этого перегружены и вызывать отказ при резервировании.

3.2.1.2. Снижение вариаций задержки

Основной целью DetNet является обеспечение возможности сведения отличных от IP сетей с критичными (sensitive) приложениями в единую сетевую инфраструктуру. Это требует аккуратной эмуляции развернутых в настоящее время под конкретные задачи сетей, которые основаны, например, на аналоговых (к примеру, с модуляцией 4 — 20 мА) и цифровых последовательных линиях (или шинах) для обеспечения надежных, синхронизированных коммуникаций без вариации задержек. Хотя задержка аналоговой передачи определяется в основном скоростью света, традиционные последовательные каналы обычно медленны (кбит/с) по сравнению с Gigabit Ethernet, а некоторая задержка, как правило, допустима. А вот чрезмерные вариации задержки могут влиять на стабильность систем управления.

Приложения, разработанные для последовательных каналов, обычно не обеспечивают компенсации вариаций задержки по причине их отсутствия в таких линиях. Для потоков DetNet обычно предполагается упорядоченная доставка и точное время приема влияет на процессы. Для объединения таких приложений желательно эмулировать все свойства последовательной линии, такие как доставку сигналов синхронизации, полную изоляцию потоков и фиксированную задержку. Хотя минимальные вариации задержки (заданные минимальной и максимальной сквозной задержкой) допустимы в DetNet, пакетные сети вносят свои ограничения. В общем случае рекомендуется применять комбинацию указанных ниже мер.

  • Синхронизация с точностью в доли микросекунды между всеми конечными системами.

  • Поле времени выполнения в пакетах приложений.

Снижение вариаций задержки обеспечивается механизмами, описанными в параграфе 4.5, которые также обеспечивают выделение ресурсов.

3.2.2. Защита сервиса

Защита сервиса нацелена на снижение или предотвращение потери пакетов в результате отказов оборудования, включая случайные ошибки в среде передачи или памяти. Такие потери можно существенно сократить за счет распределения данных по множеству не связанных между собой путей пересылки. В [RFC6372] описаны различные методы защиты сервиса, например, линейная защита 1+1. Функциональные детали дополнительного метода описаны в параграфе 3.2.2.2 и могут быть реализованы в соответствии с параграфом 3.2.2.3 или [DETNET-MPLS] для обеспечения защиты 1+n. Выбор механизмов защиты сервиса зависит от сценария и требований.

3.2.2.1. Упорядоченная доставка

Побочным эффектом защиты сервиса может быть нарушение порядка доставки, что повышает требования к буферизации пакетов на приемной стороне для корректной обработки данных. Пакеты с нарушенным порядком доставки также влияют на вариации задержки в потоке. Гарантии сервиса DetNet включают максимальное сохранение порядка доставки в качестве ограничения. Сохранение порядка было бы действительным ограничением, отражающим неприемлемость нарушения для конечных систем. Для сохранения порядка доставки в DetNet может применяться функция POF (3.2.2.2. Репликация и устранение копий).

3.2.2.2. Репликация и устранение копий

В этом параграфе описан метод защиты сервиса за счет передачи копий пакета по нескольким путям.

Подуровень сервиса DetNet включает функции PRF, PEF и POF для использования в ретрансляторах, краевых и оконечных устройствах DetNet при обработке пакетов. Эти функции могут быть включены на ретрансляторах, краевых и оконечных устройствах DetNet. Все три функции обозначают общим термином PREOF. Метод защиты сервиса за счет репликации и устранения копий пакетов включает четыре возможности, указанные ниже.

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

  • PRF реплицирует пакеты в несколько потоков участников DetNet и обычно передает их по разным путям к получателю, например, с помощью явных маршрутов, описанных в параграфе 3.2.3. Место и механизм использования PRF внутри узла DetNet определяется реализацией.

  • PEF устраняет дубликаты пакетов потока DetNet на основе данных о порядке и истории приема пакетов. На выходе PEF всегда остается один пакет. Операция может выполняться любым узлом DetNet в пути для экономии сетевых ресурсов в нисходящем направлении, особенно при наличии нескольких точек репликации. Обычно это происходит на самом краю сети DetNet, предпочтительно вблизи получателя. Место и механизм использования PEF внутри узла DetNet определяется реализацией.

  • POF использует информацию о порядке для восстановления нарушенного порядка пакетов в потоке DetNet.

Порядок применения узлом DetNet функций PEF, POF и PRF к потоку DetNet определяется реализацией.

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

В простейшем случае это эквивалентно 1) репликации каждого пакета у отправителя с двумя интерфейсами и 2) передаче их через сеть по разным путям (разделение SRLG10) к похожим двудомным получателям, которые 3) восстанавливают порядок пакетов и 4) отбрасывают дубликаты. Это обеспечивает сохранение одного пути даже при отказе некоторых промежуточных узлов DetNet. Информация о порядке служит также для обнаружения потерь.

Ретрансляторы DetNet в сети могут поддерживать репликацию и устранение копий в разных точках сетевого пути, что обеспечивает устойчивость к множественным отказам. Это показано на рисунке 1, где два ретранслятора реплицируют (R) потоки DetNet на входе, передают потоки членов DetNet другому ретранслятору и конечной системе, а также устраняют дубликаты (E) на выходном интерфейсе в сторону конечной системы справа. При отказе любого канала в сети составной поток DetNet сохраняется. Кроме того, обеспечивается работа при отказе двух каналов, если они размещены в разных сегментах сети.

              > > > > > > > ретранслятор > > > > > > >
             > /------------+ R узел E +------------\ >
            > /                  v + ^               \ >
Конечная   R +                   v | ^                + E Конечная
система      +                   v | ^                +   система
            > \                  v + ^               / >
             > \---------+ R ретранслятор E +-------/ >
              > > > > > > > > >  узел  > > > > > > > >

Рисунок 1. Репликация и исключение потоков.


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

При объединении потоков участника, проходящих по путям разной длины, может потребоваться дополнительная буферизация для выравнивания задержки на разных путях. Это выравнивание обеспечивает результирующему составному потоку соответствие ограничениям пропускной способности даже после восстановления при отказе одного из путей. Дополнительная буферизация может также служить для соблюдения порядка пакетов.

3.2.2.3. Кодирование пакетов для защиты сервиса

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

3.2.3. Явные маршруты

В сетях, управляемых типичными протоколами динамической маршрутизации, такими как IS-IS или OSPF, события в сетевой топологии той или иной части сети могут, по меньшей мере в течение короткого времени, влиять на доставку данных в участках сети, удаленных от точки отказа или восстановления. Даже использование резервных путей через сеть (например, как определено в [RFC6372]) не устраняет вероятность потери пакетов. Кроме того, побочным эффектом изменения маршрутов может быть нарушение порядка доставки.

Многие сети, работающие в реальном масштабе времени, основаны на кольце из двухпортовых устройств с относительно простым протоколом управления кольцом. Это обеспечивает резервирование пути для защиты сервиса с минимальным числом проводов. Дополнительным преимуществом кольцевой топологии часто является возможность использования протоколов управления, отличающихся от применяемых в многосвязных (mesh) сетях, и соответствующее сокращение времени отклика на изменение топологии. Недостатком кольцевой топологии является большее число этапов пересылки (hop) и соответствующий рост задержки на типичном пути.

Для получения преимуществ малого числа этапов пересылки вместе с защитой даже от очень коротких перебоев в связи DetNet использует явные маршруты, где путь данного потока DetNet не меняется сразу и может не измениться совсем в результате событий смены топологии. Защита сервиса (параграфы 3.2.2 и 3.2.2.3) при явных маршрутах обеспечивает высокую вероятность сохранения непрерывной связности. Явные маршруты можно создавать разными способами, например, с помощью RSVP-TE [RFC3209], SR11 [RFC8402], SDN [RFC8453], IS-IS [RFC7813] и т. п. Явные маршруты обычно применяются в MPLS TE12 LSP13.

Побочным эффектом распределения потока по нескольким путям может быть нарушение порядка доставки, особенно при смене одного пути на другой для комбинирования потока. Это не зависит от применяемого метода распространения и также используется для защиты сервиса по явным маршрутам. Как описано в параграфе 3.2.2.1, нарушение порядка доставки влияет на вариации задержки потока и размер буферов, требуемых для обработки данных. Поэтому гарантии сервиса DetNet включают максимальное нарушение порядка в качестве ограничения. Использование явных маршрутов помогает обеспечить упорядоченную доставку, поскольку маршрут не меняется незамедлительно при изменении топологии и смену пути можно планировать, т. к. это просто переключение маршрута.

3.3. Дополнительные цели DetNet

Многие приложения требуют от DetNet предоставления дополнительных услуг, включая использование других механизмов QoS (3.3.1. Сосуществование с обычным трафиком) и защиту от некорректно работающих передатчиков (3.3.2. Устранение отказов).

3.3.1. Сосуществование с обычным трафиком

Сеть DetNet поддерживает выделение значительной части пропускной способности потокам DetNet. Однако, независимо от объема выделенных для потоков DetNet ресурсов, целью DetNet является сосуществование с имеющимися схемами классов обслуживания (CoS14), например, DiffServ. Важно, чтобы не относящийся к DetNet трафик не нарушал потоки DetNet (см. параграф 3.3.2 и раздел 5). Поэтому возникает ряд требований.

  • Пропускная способность (возможность передачи), не занятая потоками DetNet, доступна для прочих пакетов.

  • Потоки DetNet могут формоваться или планироваться для обеспечения параметров задержки высокоприоритетных пакетов, не относящихся к DetNet.

  • При детальном планировании возможностей передачи для потоков DetNet алгоритм планирования должен оставлять достаточно возможностей передачи прочих пакетов с учетом потребностей пользователей сети. Подробное планирование также позволяет разделять буферные ресурсы по времени между потоками DetNet.

Следует избегать подавления трафика, не относящегося к DetNet, например, с помощью правил или формовки трафика (например, [RFC2475]). Таким образом, финальным эффектом наличия в сети потоков DetNet будет в основном уменьшение пропускной способности, доступной для другого трафика.

3.3.2. Устранение отказов

Отказоустойчивым системам, работающим в реальном масштабе времени, требуется снижение числа возможных отказов. В сети DetNet следует применять фильтры и правила для обнаружения приема пакетов DetNet не на том интерфейсе, не в то время или в избыточном количестве. Кроме того, фильтры и ограничители могут отбрасывать ошибочные пакеты или потоки, а также инициировать отключение сбойного потока или интерфейса.

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

Отметим, что передача потоков приложений, не применяющих контроль перегрузок на транспортном уровне в соответствии с [RFC2914], в сеть, не подготовленную для обработки такого трафика, должна считаться сбоем и пресекаться. Созданные функцией PRF потоки участников DetNet должны считаться не использующими контроль перегрузок на транспортном уровне даже при наличии такого контроля в исходных потоках приложений, поскольку PREOF может удалять индикацию перегрузки в функции PEF (например, отбрасывание, маркеры ECN, рост задержки).

Механизмы поддержки этих требований зависят от плоскости данных и реализации. Решения для плоскости данных будут описаны в соответствующих документах. Имеются также стандартизованные или стандартизуемые методы для поддержки задач по устранению отказов, которые обеспечивают высокую вероятность предотвращения влияний некорректно работающих систем на хорошо организованные потоки DetNet, за исключением отказов приемных интерфейсов, находящихся непосредственно под некорректно работающим устройством. Примерами таких методов являются функции контроля и формовки трафика (например, описанные в [RFC2475]), разделение потоков по очередям с ограничением скорости на уровне потока, а также применение активного управления очередями [RFC7567].

4. Архитектура DetNet

4.1. Модель стека DetNet

Функции DetNet (раздел 3. Обеспечение качества обслуживания в DetNet) реализованы на двух смежных подуровнях стека протоколов — сервис DetNet и пересылка DetNet. Подуровень сервиса предоставляет услуги DetNet (например, защиту сервиса) вышележащему уровню стека и приложениям. Подуровень пересылки поддерживает услуги DetNet в базовой сети, например, путем предоставления явных маршрутов и резервирования ресурсов для потоков DetNet.

4.1.1. Представление модели стека протоколов

На рисунке 2 представлена концептуальная модель уровней плоскости данных DetNet. Можно сравнить ее с моделью из [IEEE802.1CB], Annex C.

   |Пакет, проходящий|        ^ Пакет, проходящий ^
   v  вниз по стеку  v        |  вверх по стеку   |
+-----------------------+   +-----------------------+
|       Источник        |   |      Получатель       |
+-----------------------+   +-----------------------+
| Подуровень сервиса:   |   | Подуровень сервиса:   |
| Упорядочение пакетов  |   | Исключение дубликатов |
| Репликация потоков    |   | Слияние потоков       |
| Кодирование пакетов   |   | Декодирование пакетов |
+-----------------------+   +-----------------------+
| Подуровень пересылки: |   | Подуровень пересылки: |
| Выделение ресурсов    |   | Выделение ресурсов    |
| Явные маршруты        |   | Явные маршруты        |
+-----------------------+   +-----------------------+
|     Нижние уровни     |   |     Нижние уровни     |
+-----------------------+   +-----------------------+
            v                           ^
             \_________________________/

Рисунок 2. Стек протоколов плоскости данных DetNet.


Для данного приложения и даже сети могут требоваться не все подуровни из числа перечисленных ниже.

Application — приложение

На рисунке приложения показаны как отправитель и получатель.

Packet sequencing — упорядочение пакетов

Как часть сервисного подуровня DetNet, функция упорядочения пакетов представляет порядковые номера для репликации и устранения дубликатов в защите сервиса DetNet (3.2.2.2. Репликация и устранение копий) и партнером этого подуровня является исключение дубликатов. Этот подуровень не требуется, если предполагается упорядочение пакетов и устранение дубликатов для потоков DetNet вышележащим протоколом.

Duplicate elimination — исключение дубликатов

Как часть сервисного подуровня DetNet, отбрасывает все дубликаты пакетов на основе порядковых номеров, представленных партнером (упорядочение пакетов) для репликации потоков DetNet. Подуровень может работать с потоками членов и составными потоками. Репликация может также работать на основе точного времени приема в сети с планированием. Подуровень устранения дубликатов может также восстанавливать порядок пакетов в потоке, нарушенный потерей пакетов в одном из множества путей потока.

Flow replication — репликация потоков

Как часть защиты сервиса DetNet, пакеты, относящиеся к составному потоку DetNet, реплицируются в два или более потоков участника DetNet. Эта функция отделена от упорядочения пакетов. Репликация потока может быть явной репликацией и перемаркировкой или выполняться, например, на основе методов, похожих на обычную групповую репликацию с последующим выделением ресурсов. Партнером является подуровень слияния потоков.

Flow merging — слияние потоков

Как часть сервисного подуровня DetNet, функция слияния потоков объединяет потоки членов DetNet для поднимающихся по стеку пакетов, относящихся к конкретному составному потоку DetNet. Слияние потоков DetNet вместе с подуровнями упорядочения, устранения дубликатов и репликации для потоков DetNet обеспечивает репликацию и устранение дубликатов (3.2.2. Защита сервиса). Партнером служит подуровень репликации.

Packet encoding — кодирование пакетов

Как часть защиты сервиса DetNet, кодирование пакетов дополняет их упорядочение и репликацию потоков, комбинируя информацию нескольких пакетов DetNet (возможно из разных составных потоков DetNet) и передавая ее в пакетах других потоков членов DetNet. Партнером является подуровень декодирования.

Packet decoding — декодирование пакетов

Как часть защиты сервиса DetNet, декодирование пакетов дополняет слияние потоков и устранение дубликатов, беря пакеты из разных потоков членов DetNet и извлекая из них исходные пакеты составных потоков, использованных функцией кодирования. Партнером является подуровень кодирования.

Resource allocation — выделение ресурсов

Подуровень пересылки DetNet обеспечивает выделение ресурсов (4.5. Очереди, формирование, планирование и вытеснение трафика). Используемые механизмы очередей и формовки трафика обычно предоставляются базовой сетью. Они могут быть тесно связаны со способами предоставления путей для потоков DetNet. На рисунке выделение путей и ресурсов объединено.

Explicit routes — явные маршруты

Явные маршруты являются фиксированными путями, работающими на подуровне пересылки DetNet и определяемыми заранее для предотвращения воздействий схождения сетей (маршрутов) на потоки DetNet.

Функции OAM15 используют сигнализацию в основной полосе или по отдельному каналу для проверки эффективности обеспечения параметров QoS. Эти функции не показаны на рисунке 2 и могут размещаться на разных уровнях. OAM может включать специальные теги, добавляемые в пакеты для трассировки ошибок реализации или настройки сети, что позволяет определить пакеты, являющиеся репликами, найти ретрансляторы DetNet, выполняющие репликацию, и определить сегмент, предназначенный для реплики. Активные и гибридные методы OAM требуют дополнительного расхода полосы для контроля отказов и мониторинга производительности в домене DetNet. Например, OAM может генерировать специальные тестовые зонды или добавлять свою информацию в пакеты данных.

Функции репликации и устранения дубликатов могут выполняться у отправителя и получателя составного потока DetNet, а также в ретрансляторах DetNet.

4.1.2. Обзор плоскости данных DetNet

«Детерминированные сети» организуются из поддерживающих DetNet конечных систем, краевых узлов и ретрансляторов DetNet, которые совместно предоставляют услуги DetNet. Ретрансляторы и краевые узлы DetNet соединены между собой транзитными узлами DetNet (например, LSR), которые поддерживают DetNet, но не обеспечивают услуг DetNet. Все узлы DetNet подключаются к подсетям, при этом канал «точка-точка» считается вырожденной подсетью. Эти подсети обеспечивают совместимые с DetNet услуги для поддержки трафика DetNet. Примерами технологий подсетей являются MPLS TE, IEEE 802.1 TSN и OTN16. Возможны многоуровневые системы DetNet, где одна подсеть DetNet предоставляет услуги системе DetNet более высокого уровня. Простая концептуальная сеть DetNet показана на рисунке 3. Отметим, что на этом и последующих рисунках «Пересылка» и Fwd относятся к подуровню пересылки DetNet, а «сервис» и Svc — к подуровню сервиса DetNet (4.1.1. Представление модели стека протоколов).

Оконечная       Краевой      Транзитный     Ретранслятор    Оконечная
система TSN       узел          узел                   система DetNet
+----------+   +.........+                               +----------+
|Приложение|<--:Svc Proxy:--  Сквозной сервис   -------->|Приложение|
+----------+   +---------+                 +---------+   +----------+
|   TSN    |   |TSN| |Svc|<- поток DetNet--: Сервис  :-->| Сервис   |
+----------+   +---+ +---+   +--------+    +---------+   +----------+
|Пересылка |   |Fwd| |Fwd|   |  Fwd   |    |Fwd| |Fwd|   |Пересылка |
+-------.--+   +-.-+ +-.-+   +--.----.+    +-.-+ +-.-+   +---.------+
        : Канал  :    /  ,-----. \   : Канал :    /  ,-----.  \
        +........+    +-[Подсеть]-+  +.......+    +-[Подсеть]-+
                         `-----'                     `-----'

Рисунок 3. Простая сеть с поддержкой DetNet.


Плоскость данных DetNet разделена на два подуровня — сервис DetNet и пересылка DetNet. Это помогает изучать и оценивать разные комбинации доступных решений на уровне данных, некоторые из них показаны на рисунке 4. Это разделение на подуровни DetNet полезно, но не является формальным требованием. Некоторые технологии могут предоставлять услуги DetNet без выделения этих уровней.

              .
              .
+-----------------------------+
| Сервисный подуровень DetNet | PW, UDP, GRE
+-----------------------------+
| Подуровень пересылки DetNet | IPv6, IPv4, MPLS TE LSPs, MPLS SR
+-----------------------------+
              .
              .

Рисунок 4. Адаптация DetNet к уровню данных.


В некоторых сетях конечные системы исходно обеспечивают инкапсуляцию потоков DetNet со всей информацией, нужной узлам DetNet (например, потоки DetNet на основе протокола RTP17 [RFC3550], передаваемые через сети UDP/IP или псевдопровода PW18). В иных случаях формат инкапсуляции может существенно отличаться.

Имеется много вариантов организации плоскости данных для трафика DetNet за счет выбора технологического решения для подуровней сервиса пересылки DetNet.

Одним из основных различий между плоскостями данных являются базовые заголовки, используемые узлами DetNet. Например, базовый сервис может предоставляться на основе меток MPLS или заголовков IP. Этот выбор влияет на базовую логику пересылки для подуровня сервиса DetNet. Отметим, что в обоих случаях для адресации узлов DetNet служат адреса IP. Выбранная для подуровня пересылки DetNet технология тоже должна отображаться не технологию подсети, соединяющей узлы DetNet. Например, потоки DetNet могут отображаться на потоки TSN.

4.1.3. Модель эталонной сети

На рисунке 5 дано другое представление связанных с сервисом DetNet опорных точек и основных компонентов.

Интерфейсы DetNet-UNI (U на рисунке 5) в этом документе считаются опорными точками для пакетов и обеспечивают соединение с пакетной сетью. Интерфейс DetNet-UNI вожет обеспечивать множество функций, включая:

  • инкапсуляцию потоков DetNet в соответствии с сетевой технологией;

  • предоставление статуса доступности ресурсов для их резервирования;

  • предоставление услуг синхронизации для конечных систем;

  • поддержка сигнализации для организации резервирования в сети без контроллера или с использованием контроллера, работающего лишь с сетью, а не с конечными системами.

Конечная система                                     Конечная система
DetNet                                                         DetNet
   _                                                             _
  / \     +----DetNet-UNI (U)                                   / \
 /App\    |                                                    /App\
/-----\   |                                                   /-----\
| NIC |   v         ________                                  | NIC |
+--+--+   _____    /        \             DetNet-UNI (U) --+  +--+--+
   |     /     \__/          \                             |     |
   |    / +----+    +----+    \_____                       |     |
   |   /  |    |    |    |          \_______               |     |
   +------U PE +----+ P  +----+             \          _   v     |
       |  |    |    |    |    |              |     ___/ \        |
       |  +--+-+    +----+    |       +----+ |    /      \_      |
       \     |                |       |    | |   /         \     |
        \    |   +----+    +--+-+  +--+PE  |------         U-----+
         \   |   |    |    |    |  |  |    | |   \_      _/
          \  +---+ P  +----+ P  +--+  +----+ |     \____/
           \___  |    |    |    |           /
               \ +----+__  +----+     DetNet-1    DetNet-2
   |            \_____/  \___________/                           |
   |                                                             |
   |      |    Сквозное обслуживание       |     |         |     |
   <------------------------------------------------------------->
   |      |     Сервис DetNet              |     |         |     |
   |      <------------------------------------------------>     |
   |      |                                |     |         |     |

Рисунок 5. Эталонная модель сервиса DetNet (многодоменная).


Внутренние опорные конечных систем (между приложением App и NIC19) более сложны с точки зрения управления и могут предъявлять дополнительные требования (например, предполагать упорядоченную доставку во внутренние опорные точки, где не обязательно такая доставка выполняется через DetNet-UNI).

4.2. Системы DetNet

4.2.1. Конечные системы

Трафик потока приложения может иметь тип CBR (постоянная скорость) или VBR (переменная скорость) и инкапсуляцию L1, L2 или L3 (например, TDM20, Ethernet, IP). Эти характеристики являются входными данными для резервирования ресурсов и могут быть упрощены для обеспечения детерминизма при пересылке пакетов (например, резервирование для пиковой скорости трафика VBR и т. п.).

Конечная система может не знать о подуровне пересылки или сервиса DetNet, т. е. не включать относящихся к DetNet функций. Системы с функциональностью DetNet в домене DetNet могут применять один или разные подуровни пересылки. Категории конечных систем показаны на рисунке 6.

          Конечная система
                 |
                 |
                 |  DetNet поддерживается?
                / \
        +------<   >------+
    нет |       \ /       | да
        |        v        |
 Конечная система,        |
 не понимающая DetNet     |
                          | Подуровни сервиса и
                          | пересылки 
                         / \  поддерживаются?
               +--------<   >-------------+
Поддерживается |         \ /              | Поддерживается
пересылка      |          v               | сервис
               |          | Поддерживаются|
               |          | оба           |
       Конечная система   |         Конечная система
       с пересылкой DetNet|         с сервисом  DetNet
                          v
                    Конечная система
                    с пересылкой и сервисом

Рисунок 6. Категории конечных систем.


Ниже перечислены примеры известных конечных систем.

DetNet unaware — без поддержки DetNet

Классический вариант, требующий промежуточное устройство (прокси).

DetNet f-aware — с поддержкой пересылки DetNet

Система, которая знает о подуровне пересылки DetNet. Ей известны некоторые функции TSN (например, резервирование), но неизвестно о защите сервиса.

DetNet s-aware — с поддержкой сервиса DetNet

Система, которая знает о подуровне сервиса DetNet. Она предоставляет порядковые номера, но не знает о выделении ресурсов.

DetNet sf-aware — с поддержкой пересылки и сервиса DetNet

Полнофункциональная конечная система DetNet. Она поддерживает функции DetNet и обычно использует ту же парадигму пересылки, которая применяется в подключенном домене DetNet. Может считаться встроенной частью домена DetNet.

4.2.2. Ретрансляторы, краевые и транзитные узлы DetNet

Как показано на рисунке 3, краевые узлы DetNet служат посредниками (proxy), ретрансляторы DetNet, обеспечивающие подуровень сервиса DetNet, знают о DetNet, а транзитным узлам DetNet нужно знать лишь о подуровне пересылки.

В общем случае поток DetNet проходит через один или множество узлов, не знающих о DetNet, между двумя узлами DetNet, обеспечивающими подуровень пересылки DetNet для этого потока. Здесь могут возникать нарушения или отказы DetNet QoS. Администраторы сетей должны 1) обеспечить настройку не знающих о DetNet узлов для минимизации потерь и задержки пакетов, а также 2) предоставить достаточное буферное пространство на транзитных узлах DetNet, которые следуют за узлами, не поддерживающими DetNet, для компенсации вариаций задержки.

4.3. Потоки DetNet

4.3.1. Типы потоков DetNet

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

App-flow — поток приложения

Данные, передаваемые в потоке DetNet между двумя не знающими о DetNet конечными системами. App-flow не включает связанных с DetNet атрибутов и не задает конкретных требований к узлам DetNet.

DetNet-f-flow — поток, знающий о пересылке

Конкретный формат потока DetNet, требующий выделения ресурсов от подуровня пересылки DetNet.

DetNet-s-flow — поток, знающий о сервисе

Конкретный формат потока DetNet, требующий защиты сервиса от подуровня сервиса DetNet.

DetNet-sf-flow — поток, знающий о пересылке и сервисе

Конкретный формат потока DetNet, требующий функции подуровней пересылки и сервиса DetNet при доставке.

4.3.2. Поведение источника передачи

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

Асинхронные потоки DetNet не скоординированы с точным расписанием, поэтому ретрансляторы и конечные системы должны предполагать худший вариант взаимодействия разных потоков DetNet при использовании буферных ресурсов. Асинхронные потоки DetNet характеризуются:

  • максимальным размером пакетов;

  • интервалом наблюдения;

  • максимальным числом передач в течение интервала наблюдения.

Эти параметры вместе с информацией о применяемом стеке протоколов (и размере добавляемых в пакет заголовков) позволяют определить пропускную способность, требуемую для потока DetNet.

При использовании сервиса DetNet источник должен соблюдать заданные пределы. При передаче меньшего объема данных неиспользуемые ресурсы (такие, как пропускная способность) могут быть отданы системой DetNet для другого трафика, пока все гарантии соблюдаются. Предоставление свободных ресурсов другим потокам DetNet не имеет смысла. Эти потоки DetNet имеют выделенные им ресурсы в предположении, что все потоки DetNet могут использовать ресурсы в течение длительного времени.

В DetNet не предполагается, что потоки приложений будут реагировать на уведомления о перегрузке [RFC2914] или [RFC3168]. Предполагается, что для осмысленности потока DetNet он должен доставляться целиком. Т. е. приложения для работы в реальном масштабе времени, представляющие интерес для DetNet, требуют, чтобы потеря данных в сети была минимальной.

Хотя DetNet стремится минимизировать изменения, которые нужно внести в приложения для перехода от цифровых сетей специального назначения к сетям IP, не удается избавиться от необходимости выделения ресурсов до запуска приложения. Во-первых, сеть не может обеспечить конечную задержку и практически нулевую потерю пакетов при произвольно высоком уровне загрузки. Во-вторых, для достижения практически нулевой потери пакетов в потоках DetNet узлам DetNet требуются выделенные буферы для конкретных потоков или классов потоков DetNet. Требования каждого резервирования должны преобразовываться в параметры, управляющие в каждой системе DetNet очередями, формовкой и планированием трафика, которые должны быть распространены между узлами и конечными системами.

Предполагается, что все узлы в домене DetNet будут обеспечивать поведение, требуемое для предоставления конкретного сервиса DetNet. Если сам узел не знает о сервисе DetNet, смежные с ним узлы DetNet должны обеспечить ему подобающую поддержку сервиса DetNet. Например, узел IEEE 802.1 TSN можно использовать для соединения узлов DetNet и эти узлы могут отображать потоки DetNet на потоки 802.1 TSN. Другим примером является домен MPLS-TE или MPLS-TP21, используемый для соединения узлов DetNet, которые могут отображать потоки DetNet на TE LSP, обеспечивающие требования QoS для сервиса DetNet.

4.3.3. Неполные сети

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

4.4. Организация трафика для DetNet

TEAS22 [TEAS] определяет архитектуру организации трафика, применимую для пакетных и иных сетей. С точки зрения TEAS организацией трафика (TE23) считаются методы, позволяющие операторам управлять обработкой определенных потоков трафика в своих сетях.

Благодаря созданию явных оптимизированных путей, DetNet можно считать новой, специализированной ветвью TE, наследующей архитектуру с разделением по плоскостям (уровням). Архитектура DetNet включает три плоскости — (пользовательские) приложения, контроллер и сеть. Это похоже на уровни, приведенные на рисунке 1 в Software-Defined Networking (SDN): Layers and Architecture Terminology [RFC7426], и контроллеры из [RFC8453] и [RFC7149].

4.4.1. Плоскость приложений

В соответствии [RFC7426] плоскость приложений включает приложения и службы. В частности, здесь присутствует пользовательский агент — специализированное приложение, взаимодействующее с конечным пользователем и оператором для запроса услуг DetNet с помощью элемента управления потоком (FME24), который может размещаться в одной из конечных систем.

В плоскости приложений интерфейс управления позволяет согласовать потоки между конечными системами. Представление обеспечивается абстракцией потока TSpec25, используемой для размещения резервирования на (северном) интерфейсе сервиса и в плоскости приложения. Это связано с абстракцией местоположения, такой как адрес IP или имя (DNS), для идентификации конечных систем и, возможно, задания узлов DetNet.

4.4.2. Плоскость контроллера

Плоскость контроллера соответствует плоскостям Control и Management в [RFC7426], хотя CCAMP26 (в соответствии с определением рабочей группы CCAMP [CCAMP]) задает дополнительное различие между управлением и измерениями. Когда различие между элементами управления, измерений и другими объектами управления (Management) не существенно, для упрощения применяется термин «плоскость контроллера» (представляет все), а CPF27 указывает любое устройство, работающее в этой плоскости, будь то PCE28 [RFC4655], NME29 или протокол распределенного управления. CPF является основным элементом контроллера, отвечающим за расчет детерминированных путей, применяемых в сетевой плоскости.

(Северный) интерфейс сервиса позволяет приложениям из прикладной плоскости взаимодействовать с объектами плоскости контроллера, как показано на рисунке 7.

Конечная                                             Конечная
система                                               система

-+-+-+-+-+-+-+ Северная граница -+-+-+-+-+-+-+-+-+-+-+-+-+-+-

          CPF         CPF              CPF              CPF

-+-+-+-+-+-+-+ Южная граница +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-

             Узел       Узел       Узел       Узел
            DetNet     DetNet     DetNet     DetNet
 NIC                                                     NIC
            Узел       Узел       Узел       Узел
           DetNet     DetNet     DetNet     DetNet

Рисунок 7. Интерфейсы северной и южной границы.


Несколько CPF могут действовать совместно для реализации запросов от FME как поведения на уровне потока или интервала (hop), задаваемого на узлах DetNet для каждого отдельного потока. CPF размещают каждый поток через детерминированный набор узлов DetNet, чтобы выполнить ограничения на уровне потоков (такие как защита и задержки) и оптимизировать общий результат по таким показателям, как абстрактная агрегированная стоимость. Детерминированная структура обычно сложней прямого назначения и включает резервные пути с одной или несколькими точками репликации и устранения дубликатов. Большие сети рассматриваются в разделе 4.9.

4.4.3. Плоскость сети

Плоскость сети представляет сетевые устройства и протоколы в целом, независимо от уровня, на котором работают устройства. Плоскость включает уровни (плоскости) данных и операций (например, OAM).

Плоскость сети включает сетевые адаптеры (NIC) в конечных системах, которые обычно являются хостами IP, и узлах DetNet, которыми обычно служат маршрутизаторы IP и коммутаторы MPLS.

Южный (сетевой) интерфейс позволяет объектам плоскости контроллера взаимодействовать с устройствами в плоскости сети, как показано на рисунке 7. Этот интерфейс использует и расширяет TEAS для описания физической топологии и ресурсов в плоскости сети.

Узлы DetNet (и, возможно, сетевые адаптеры конечных систем) раскрывают свои возможности и физические ресурсы контроллеру (CPF) и обновляют CPF своим динамическим восприятием топологии через южный интерфейс. В ответ CPF организуют пути на уровне потоков, обеспечивая характеристики потока, которые более тесно связаны с работой узла DetNet, нежели TSpec.

В сетевой плоскости узлы DetNet могут обмениваться информацией о состоянии путей между смежными узлами DetNet и, возможно, к конечным системам и пересылать пакеты в рамках ограничений, связанных с каждым потоком, или (при невозможности пересылки) выполнять такие операции, как отбрасывание или деклассификация.

В этом документе основное внимание уделено южному интерфейсу и сетевой плоскости.

4.5. Очереди, формирование, планирование и вытеснение трафика

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

Стандартные алгоритмы организации очередей и выбора передачи позволяют TE (4.4. Организация трафика для DetNet) рассчитать вклад задержки на каждом узле в общую задержку DetNet, размер буферов на каждом узле DetNet для каждого инкрементного потока DetNet, а также, что более важно, преобразовать спецификацию потока в набор значений для объектов управления на каждом ретрансляторе и конечной системе. Например, рабочая группа IEEE 802.1 задала набор алгоритмов очередей, формовки и планирования, позволяющий каждому узлу DetNet или центральному контроллеру рассчитать эти значения. Эти алгоритмы включают:

  • формовщик на основе кредитов [IEEE802.1Qav] (включено в [IEEE802.1Q]);

  • очереди с ограничением по времени и чередующимся расписанием на основе синхронизированных часов [IEEE802.1Qbv] (включен во [IEEE802.1Q]);

  • синхронизированные двойные (или тройные) буферы, управляемые синхронизированными часами [IEEE802.1Qch] (включено в [IEEE802.1Q]);

  • вытеснение передачи пакетов Ethernet пакетами с более строгими требованиями к задержке [IEEE802.1Qbu] (включен в [IEEE802.1Q]) [IEEE802.3br] (включено в [IEEE802.3]).

Хотя эти методы в настоящее время включены лишь в стандарты Ethernet [IEEE802.3] и мостов, следует отметить, что они (за исключением, возможно, вытеснения пакетов) применимы к средам иных типов, а также к маршрутизаторам. В других средах могут применяться свои методы (например, [TSCH-ARCH] и [RFC7554]). В IETF также разработаны свои методы (например, [RFC8289] и [RFC8033]). DetNet может включить эти определения в будущем и описать их применение на узлах DetNet.

4.6. Экземпляр сервиса

Экземпляр сервиса представляет все функции, нужные на узле DetNet для организации сквозного сервиса между UNI.

Эталонная модель сети DetNet показана на рисунке 8 для сервиса DetNet (т. е. между парой DetNet-UNI). На рисунке конечные системы (A и B) подключены напрямую к граничным узлам сети IP/MPLS (PE1 и PE2). Для конечных систем, участвующих в коммуникациях DetNet, подключение может потребоваться до организации потока приложения, которому нужны услуги DetNet. Такой экземпляр сервиса, относящийся к подключению, и экземпляр, выделенный для сервиса DetNet, используют общий доступ. Пакеты, относящиеся к потоку DetNet, выбираются фильтром, настроенным для доступа (F1 и F2). В результате связанный с потоком доступ (Доступ-A + F1 и Доступ-B + F2) завершается в связанном с потоком экземпляре сервиса (SI-1 и SI-2). Туннель обеспечивает связность экземпляров.

             Доступ-A                                     Доступ-B
              <----->    <-------- Туннель --------->     <----->

                 +---------+        ___  _        +---------+
 Конечная система|  +----+ |       /   \/ \_      | +----+  | Конечная система
       "A" -------F1+    | |      /   Сеть  \     | |    +F2----- "B"
                 |  |    +========+ IP/MPLS +=======+    |  |
                 |  |SI-1| |      \__      _/     | |SI-2|  |
                 |  +----+ |         \____/       | +----+  |
                 |PE1      |                      |      PE2|
                 +---------+                      +---------+

Рисунок 8. Эталонная модель сети DetNet.


Туннель используется исключительно для пакетов потока DetNet между SI-1 и SI-2. Экземпляры сервиса настроены на реализацию функций DetNet и связанной с потоком пересылки DetNet. Экземпляры и туннель могут поддерживать несколько потоков DetNet. Для совместного использования экземпляров сервиса несколькими потоками нужно соответственно заполнить таблицы пересылки этих экземпляров.

Туннель может иметь особые свойства. Например, в DetNet L3 имеются отличия использования PW для трафика DetNet от модели, описанной в [RFC6658]. В варианте DetNet псевдопровод PW служит лишь для потока DetNet, тогда как в [RFC6658] сказано:

Пакетный PW выглядит для клиентского уровня как один канал «точка-точка». Организация и поддержка смежности на сетевом уровне между клиентскими устройствами будет следовать обычной практике поддержки нужных отношений на уровне клиентов.

и

Этот пакетный псевдопровод используется для транспортировки всех протоколов L2 и L3 между LSR1 и LSR2.

Дополнительные детали зависят от сетевой технологии и описаны в [DETNET-FRAMEWORK].

4.7. Идентификация потоков на границах технологии

В этом разделе описаны действия, которые нужно выполнять на границах технологий, включая Ethernet, как одну из них. Идентификация потоков для плоскостей данных MPLS и IP описана в [DETNET-MPLS] и [DETNET-IP].

4.7.1. Экспорт идентификации потоков

Узлу DetNet может потребоваться отобразить конкретные потоки на потоки нижележащих уровней (Stream) для обеспечения требуемых услуг по управлению очередями и формовке трафика.

  • Конечная система-источник L2 (не IP) X может передавать множество потоков другой конечной системе L2 Y. Эти потоки могут включать потоки DetNet с разными требованиями QoS, а также потоки иного трафика.

  • Маршрутизатор может передавать любое число потоков другому маршрутизатору. Здесь также могут быть потоки DetNet с разными требованиями QoS и потоки, не относящиеся к DetNet.

  • Два маршрутизатора могут быть разделены мостами. Чтобы мосты могли организовать очереди и формовку на уровне потоков, им нужно идентифицировать отдельные потоки.

  • Маршрутизатор LER может иметь LSP для обслуживания трафика, направленного по конкретному адресу IP и содержащего лишь не относящиеся к DetNet потоки. При запросе потока DetNet в тот же адрес может потребоваться отдельный LSP, чтобы все маршрутизаторы LSR в пути к получателю обеспечили нужные очереди и формовку трафика.

Необходимость информирования нижележащих уровней о потоках не уникальна для DetNet. Но с учетом сложности уровней и ретрансляции через туннели, которые доступны разработчикам, в DetNet требуется модель идентификации потоков, которая лучше просмотра пакетов. Это не означает, что не будет применяться просмотр пакетов на уровне L4/L5 или возможность стандартизована, однако возможны варианты.

Ретранслятор DetNet может направлять потоки DetNet по разным путям, используя разные методы идентификации.

  • Одиночному потоку DetNet от маршрутизатора A, проходящему через сеть мостов в маршрутизатор B, можно назначить идентификатор TSN Stream, уникальный для сети мостов. После этого мосты смогут узнавать поток без просмотра заголовков вышележащих уровней. Принимающий маршрутизатор также должен понимать и воспринимать TSN Stream.

  • Потоку DetNet от LSR A к LSR B можно назначить метку, отличающуюся от метки другого трафика в тот же IP.

В обоих случаях имеющийся поток DetNet может содержать в себе множество других потоков DetNet (не путайте составные потоки и потоки участников DetNet). Для этого требуется корректная подготовка потока DetNet для передачи агрегированных потоков.

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

4.7.2. Отображение атрибутов потока между уровнями

Пересылка пакетов потока DetNet через домены с разной технологией может потребовать от нижних уровней осведомленности о конкретных потоках вышележащих уровней. Такой «экспорт идентификации потоков» требуется всякий раз, когда в пути меняется парадигма пересылки (например, пара LSR соединена через домен мостов L2). В DetNet рассматриваются три типичных метода пересылки:

  • маршрутизация IP;

  • коммутация по меткам MPLS;

  • мосты Ethernet.

add/remove     add/remove
Eth Flow-ID    IP Flow-ID
    |             |
    v             v
 +-----------------------------------------------------------+
 |      |      |      |                                      |
 | Eth  | MPLS |  IP  |     Данные приложения                |
 |      |      |      |                                      |
 +-----------------------------------------------------------+
           ^
           |
       add/remove
      MPLS Flow-ID

Рисунок 9. Пакет с множеством Flow-ID.


На рисунке 9 показан пакет с несколькими Flow-ID и указаны точки добавления и удаления каждого Flow-ID.

Дополнительными (в зависимости от домена) Flow-ID могут быть:

  • идентификаторы, созданные специальной функцией домена;

  • идентификаторы, полученные добавлением Flow-ID к App-flow.

Значение Flow-ID должно быть уникальным в рамках домена. Отметим, что Flow-ID, добавляемые к App-flow, продолжают оставаться в пакетах, но некоторые узлы могут не иметь функций для их распознавания, поэтому используется дополнительный Flow-ID.

4.7.3. Примеры отображений Flow-ID

Узлы IP и MPLS предполагаются настроенными на вталкивание дополнительных (зависящих от домена) Flow-ID при передаче трафика коммутатору Ethernet, как показано в примерах ниже.

На рисунке 10 показана конечная система IP (IP-A), подключенная через два коммутатора Ethernet (ETH-n) к маршрутизатору IP (IP-1).

                                        Домен IP
                     <----------------------------------------------->

              +======+                                       +======+
              |L3-ID |                                       |L3-ID |
              +======+  /\                           +-----+ +======+
                       /  \       Пересылка          |     |
                      /IP-A\      по ETH-ID          |IP-1 |  Распознавание
Вталкивание ------>  +-+----+         |              +---+-+  <----- ETH-ID
   ETH-ID           |         +----+-----+            |
                    |         v          v            |
                    |      +-----+    +-----+         |
                    +------+     |    |     +---------+
           +......+        |ETH-1+----+ETH-2|           +======+
           .L3-ID .        +-----+    +-----+           |L3-ID |
           +======+             +......+                +======+
           |ETH-ID|             .L3-ID .                |ETH-ID|
           +======+             +======+                +------+
                                |ETH-ID|
                                +======+

                             Домен Ethernet
                           <---------------->

Рисунок 10. Соединение узлов IP через домен Ethernet.


Система IP-A использует исходный идентификатор потока приложения L3-ID, но она подключена к домену Ethernet, поэтому помещает в пакет, связанный с этим доменом, Flow-ID (ETH-ID) перед отправкой пакета ETH-1. Коммутатор ETH-1 может распознать поток по ETH-ID и пересылает его ETH-2, который коммутирует пакет маршрутизатору IP. Маршрутизатор IP-1 должен быть настроен на прием группового потока, указанного Ethernet Flow-ID. Он является устройством L3 и декодирует идентификатор потока данных по полям L3-ID в полученных пакетах.

На рисунке 11 показаны узлы домена MPLS (PE-n и P-m) соединенные через два коммутатора Ethernet (ETH-n).

                                       Домен MPLS
                     <----------------------------------------------->

          +=======+                                  +=======+
          |MPLS-ID|                                  |MPLS-ID|
          +=======+  +-----+                 +-----+ +=======+ +-----+
                     |     |   Пересылка     |     |           |     |
                     |PE-1 |   по ETH-ID     | P-2 +-----------+ PE-2|
Вталкивание  ----->  +-+---+        |        +---+-+           +-----+
   ETH-ID           |      +-----+----+       |  \ Распознавание
                    |      v          v       |   +-- ETH-ID
                    |   +-----+    +-----+    |
                    +---+     |    |     +----+
           +.......+    |ETH-1+----+ETH-2|   +=======+
           .MPLS-ID.    +-----+    +-----+   |MPLS-ID|
           +=======+                         +=======+
           |ETH-ID |         +.......+       |ETH-ID |
           +=======+         .MPLS-ID.       +-------+
                             +=======+
                             |ETH-ID |
                             +=======+
                          Домен Ethernet 
                        <---------------->

Рисунок 11. Соединение узлов MPLS через домен Ethernet.


PE-1 использует идентификатор MPLS-ID, но этот узел подключен к домену Ethernet и вталкивает идентификатор для этого домена (ETH-ID) перед отправкой пакета ETH-1. Коммутатор ETH-1 может распознать поток данных по ETH-ID и пересылает его ETH-2, который коммутирует пакеты узлу MPLS (P-2). Узел P-2 должен быть настроен на получение группового потока по Ethernet Flow-ID. Он является узлом MPLS и декодирует идентификатор потока данных по полям MPLS-ID в принятых пакетах.

Из приведенных примеров можно понять, что при изменении или экспорте способов идентификации потока DetNet нужно соответствующим образом менять или экспортировать средства информирования о порядковых номерах.

4.8. Анонсирование ресурсов, возможностей и соседства

Для подготовки сервиса DetNet нужно иметь указанные ниже сведения.

  • Данные о возможностях системы DetNet, которые нужны для точного выделения ресурсов этой и другим системам DetNet. Это включает, например, реализуемые алгоритмы очередей и формирования трафика (4.5. Очереди, формирование, планирование и вытеснение трафика), объем буферов для выделения DetNet, наихудшие допустимые задержка и нарушение порядка доставки.

  • Фактическое состояние ресурсов DetNet на узле DetNet.

  • Идентификационные данные соседей системы DetNet и характеристики каналов между системами DetNet, включая задержку в наносекундах.

4.9. Большие сети

Резервирование для отдельных потоков DetNet требует обширной информации о состоянии в каждом узле DetNet, особенно если требуется адекватное устранение отказов (3.3.2. Устранение отказов). Плоскость данных DetNet для поддержки большого числа потоков DetNet должна обеспечивать агрегирование потоков DetNet. Такие агрегированные потоки могут рассматриваться плоскостями данных узлов DetNet как отдельные потоки DetNet. Без такого агрегирования система на уровне ретранслятора может ограничивать размеры сетей DetNet. Примеры используемых методов включают иерархию MPLS и коды IP DiffServ (DSCP).

4.10. Совместимость с уровнями L2

Стандарты, обеспечивающие похожие возможности в сетях на основе (лишь) мостов, были созданы в IEEE 802 LAN/MAN Standards Committee. Представленная архитектура описывает абстрактную модель, которая может применяться к L2 и L3, а также к каналам, не определенным IEEE 802.

Конечные системы с поддержкой DetNet и узлы DetNet могут соединяться через подсети, т. е. технологией L2. Эти подсети будут предоставлять совместимые с DetNet услуги для поддержки трафика DetNet. Примеры технологий таких подсетей включают MPLS TE, IEEE 802.1 TSN и каналы точка-точка в OTN. Возможны и многоуровневые системы DetNet, где сеть DetNet выступает в качестве подсети для системы DetNet более высокого уровня.

5. Вопросы безопасности

Вопросы безопасности DetNet подробно рассмотрены в [DETNET-SECURITY]. Здесь обсуждаются лишь вопросы безопасности, связанные в архитектурой DetNet.

Уникальными для DetNet аспектами безопасности являются вопросы QoS в DetNet, которые связаны с максимально низкой потерей пакетов и ограниченной сквозной задержкой. DetNet может работать на основе MPLS или IP (v4 и v6), наследуя их защитные свойства в плоскостях данных и управления.

Вопросы безопасности для DetNet ограничены (например, по сравнению с открытой сетью Internet), DetNet работает только внутри одного административного домена (1. Введение). В первую очередь нужно обеспечить безопасность запроса и управления ресурсами DetNet, конфиденциальность данных DetNet и доступность DetNet QoS.

Для защиты запросов и управления ресурсами DetNet может применяться аутентификация и контроль полномочий для каждого устройства, подключенного к домену DetNet, что наиболее важно для устройств управления сетью. Управление сетью DetNet может быть централизованным или распределенным (внутри административного домена). Для централизованного управления вопросы безопасности в сетях ACTN30 рассмотрены в разделе 9 [RFC8453]. При использовании протоколов распределенного управления предполагается, что безопасность DetNet обеспечивается свойствами применяемых протоколов. В любом случае возможности манипулировать административно задаваемыми параметрами предоставляются лишь уполномоченным элементам (лицам).

Для обеспечения конфиденциальности данных в DetNet потоки приложений можно защищать с использованием возможностей базовой технологии. Например, может применяться шифрование, обеспечиваемое IPsec [RFC4301] для потоков IP и MACSec [IEEE802.1AE] для потоков Ethernet (L2).

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

Для обеспечения бесперебойной доступности DetNet QoS могут применяться меры защиты от DoS-атак и добавления задержек. Для защиты от атак на службы (DoS) избыточный трафик злонамеренных или неисправных устройств можно предотвращать или ослаблять, например, с помощью контроля допуска трафика на входе в домен DetNet, как описано в параграфе 3.2.1, или с помощью методов устранения отказов, описанных в параграфе 3.3.2. Для предотвращения задержки пакетов устройствами за пределами домена DetNet выбор технологии DetNet может смягчить MITM31-атаки, например, за счет аутентификации и контроля полномочий устройств внутри домена DetNet.

Поскольку механизмы DetNet и приложения, опирающиеся на DetNet, могут широко применять методы, требующие синхронизации часов, точность, доступность и целостность синхронизации очень важны. Этот вопрос рассмотрен в [RFC7384].

Известны случаи применения к DetNet самых разных требований безопасности. Целью этого раздела является предоставление основы для решения общих проблем безопасности всех вариантов и реализаций DetNet без учета специфики инфраструктуры защиты, которая может не подойти для конкретного случая. Предполагается, что при разработке и реализации систем DetNet будут учитываться особенности конкретного устройства и реализаций.

6. Вопросы конфиденциальности

DetNet обеспечивает QoS и для этих механизмов применяются базовые соображения. В частности, маркировка позволяет атакующим сопоставить потоки или выбрать определенный тип потока для более предметного анализа.

Требование к каждому (или почти каждому) узлу пути потока DetNet идентифицировать потоки DetNet может открывать новую возможность атак на конфиденциальность, если парадигма DetNet будет использоваться более широко.

7. Взаимодействие с IANA

Документ не требует действий со стороны IANA.

8. Литература

[BUFFERBLOAT] Gettys, J. and K. Nichols, «Bufferbloat: Dark Buffers in the Internet», DOI 10.1145/2063176.2063196, Communications of the ACM, Volume 55, Issue 1, January 2012, <https://doi.org/10.1145/2063176.2063196>.

[CCAMP] IETF, «Common Control and Measurement Plane (ccamp)», October 2019, <https://datatracker.ietf.org/wg/ccamp/charter/>.

[DETNET-FRAMEWORK] Varga, B., Farkas, J., Berger, L., Fedyk, D., Malis, A., Bryant, S., and J. Korhonen, «DetNet Data Plane Framework», Work in Progress32, Internet-Draft, draft-ietf-detnet-data-plane-framework-02, 13 September 2019, <https://tools.ietf.org/html/draft-ietf-detnet-data-plane-framework-02>.

[DETNET-IP] Varga, B., Farkas, J., Berger, L., Fedyk, D., Malis, A., Bryant, S., and J. Korhonen, «DetNet Data Plane: IP», Work in Progress33, Internet-Draft, draft-ietf-detnet-ip-01, 1 July 2019, <https://tools.ietf.org/html/draft-ietf-detnet-ip-01>.

[DETNET-MPLS] Varga, B., Farkas, J., Berger, L., Fedyk, D., Malis, A., Bryant, S., and J. Korhonen, «DetNet Data Plane: MPLS», Work in Progress, Internet-Draft, draft-ietf-detnet-mpls-01, 1 July 2019, <https://tools.ietf.org/html/draft-ietf-detnet-mpls-0134>.

[DETNET-SECURITY] Mizrahi, T., Grossman, E., Hacker, A., Das, S., Dowdell, J., Austad, H., Stanton, K., and N. Finn, «Deterministic Networking (DetNet) Security Considerations», Work in Progress, Internet-Draft, draft-ietf-detnet-security-05, 29 August 2019, <https://tools.ietf.org/html/draft-ietf-detnet-security-0535>.

[IEC-62439-3] IEC, «Industrial communication networks — High availability automation networks — Part 3: Parallel Redundancy Protocol (PRP) and High-availability Seamless Redundancy (HSR)», TC 65 / SC 65C, IEC 62439-3:2016, March 2016, <https://webstore.iec.ch/publication/24447>.

[IEEE802.1AE] IEEE, «IEEE Standard for Local and metropolitan area networks-Media Access Control (MAC) Security», IEEE 802.1AE-2018, <https://ieeexplore.ieee.org/document/8585421>.

[IEEE802.1BA] IEEE, «IEEE Standard for Local and metropolitan area networks—Audio Video Bridging (AVB) Systems», IEEE 802.1BA-2011, <https://ieeexplore.ieee.org/document/6032690>.

[IEEE802.1CB] IEEE, «IEEE Standard for Local and metropolitan area networks—Frame Replication and Elimination for Reliability», DOI 10.1109/IEEESTD.2017.8091139, IEEE 802.1CB-2017, October 2019, <https://ieeexplore.ieee.org/document/8091139>.

[IEEE802.1Q] IEEE, «IEEE Standard for Local and Metropolitan Area Network—Bridges and Bridged Networks», IEEE 802.1Q-2018, <https://ieeexplore.ieee.org/document/8403927>.

[IEEE802.1Qav] IEEE, «IEEE Standard for Local and Metropolitan Area Networks — Virtual Bridged Local Area Networks Amendment 12: Forwarding and Queuing Enhancements for Time-Sensitive Streams», IEEE 802.1Qav-2009, <https://ieeexplore.ieee.org/document/5375704>.

[IEEE802.1Qbu] IEEE, «IEEE Standard for Local and metropolitan area networks — Bridges and Bridged Networks — Amendment 26: Frame Preemption», IEEE 802.1Qbu-2016, <https://ieeexplore.ieee.org/document/7553415>.

[IEEE802.1Qbv] IEEE, «IEEE Standard for Local and metropolitan area networks — Bridges and Bridged Networks — Amendment 25: Enhancements for Scheduled Traffic», IEEE 802.1Qbv-2015, <https://ieeexplore.ieee.org/document/7440741>.

[IEEE802.1Qch] IEEE, «IEEE Standard for Local and metropolitan area networks—Bridges and Bridged Networks—Amendment 29: Cyclic Queuing and Forwarding», IEEE 802.1Qch-2017, <https://ieeexplore.ieee.org/document/7961303>.

[IEEE802.1TSNTG] IEEE, «Time-Sensitive Networking (TSN) Task Group», <https://1.ieee802.org/tsn/>.

[IEEE802.3] IEEE, «IEEE Standard for Ethernet», IEEE 802.3-2018, <https://ieeexplore.ieee.org/document/8457469>.

[IEEE802.3br] IEEE, «IEEE Standard for Ethernet Amendment 5: Specification and Management Parameters for Interspersing Express Traffic», IEEE 802.3br, <https://ieeexplore.ieee.org/document/7900321>.

[RFC2205] Braden, R., Ed., Zhang, L., Berson, S., Herzog, S., and S. Jamin, «Resource ReSerVation Protocol (RSVP) — Version 1 Functional Specification», RFC 2205, DOI 10.17487/RFC2205, September 1997, <https://www.rfc-editor.org/info/rfc2205>.

[RFC2475] Blake, S., Black, D., Carlson, M., Davies, E., Wang, Z., and W. Weiss, «An Architecture for Differentiated Services», RFC 2475, DOI 10.17487/RFC2475, December 1998, <https://www.rfc-editor.org/info/rfc2475>.

[RFC2914] Floyd, S., «Congestion Control Principles», BCP 41, RFC 2914, DOI 10.17487/RFC2914, September 2000, <https://www.rfc-editor.org/info/rfc2914>.

[RFC3168] Ramakrishnan, K., Floyd, S., and D. Black, «The Addition of Explicit Congestion Notification (ECN) to IP», RFC 3168, DOI 10.17487/RFC3168, September 2001, <https://www.rfc-editor.org/info/rfc3168>.

[RFC3209] Awduche, D., Berger, L., Gan, D., Li, T., Srinivasan, V., and G. Swallow, «RSVP-TE: Extensions to RSVP for LSP Tunnels», RFC 3209, DOI 10.17487/RFC3209, December 2001, <https://www.rfc-editor.org/info/rfc3209>.

[RFC3550] Schulzrinne, H., Casner, S., Frederick, R., and V. Jacobson, «RTP: A Transport Protocol for Real-Time Applications», STD 64, RFC 3550, DOI 10.17487/RFC3550, July 2003, <https://www.rfc-editor.org/info/rfc3550>.

[RFC4301] Kent, S. and K. Seo, «Security Architecture for the Internet Protocol», RFC 4301, DOI 10.17487/RFC4301, December 2005, <https://www.rfc-editor.org/info/rfc4301>.

[RFC4655] Farrel, A., Vasseur, J.-P., and J. Ash, «A Path Computation Element (PCE)-Based Architecture», RFC 4655, DOI 10.17487/RFC4655, August 2006, <https://www.rfc-editor.org/info/rfc4655>.

[RFC6372] Sprecher, N., Ed. and A. Farrel, Ed., «MPLS Transport Profile (MPLS-TP) Survivability Framework», RFC 6372, DOI 10.17487/RFC6372, September 2011, <https://www.rfc-editor.org/info/rfc6372>.

[RFC6658] Bryant, S., Ed., Martini, L., Swallow, G., and A. Malis, «Packet Pseudowire Encapsulation over an MPLS PSN», RFC 6658, DOI 10.17487/RFC6658, July 2012, <https://www.rfc-editor.org/info/rfc6658>.

[RFC7149] Boucadair, M. and C. Jacquenet, «Software-Defined Networking: A Perspective from within a Service Provider Environment», RFC 7149, DOI 10.17487/RFC7149, March 2014, <https://www.rfc-editor.org/info/rfc7149>.

[RFC7384] Mizrahi, T., «Security Requirements of Time Protocols in Packet Switched Networks», RFC 7384, DOI 10.17487/RFC7384, October 2014, <https://www.rfc-editor.org/info/rfc7384>.

[RFC7426] Haleplidis, E., Ed., Pentikousis, K., Ed., Denazis, S., Hadi Salim, J., Meyer, D., and O. Koufopavlou, «Software-Defined Networking (SDN): Layers and Architecture Terminology», RFC 7426, DOI 10.17487/RFC7426, January 2015, <https://www.rfc-editor.org/info/rfc7426>.

[RFC7554] Watteyne, T., Ed., Palattella, M., and L. Grieco, «Using IEEE 802.15.4e Time-Slotted Channel Hopping (TSCH) in the Internet of Things (IoT): Problem Statement», RFC 7554, DOI 10.17487/RFC7554, May 2015, <https://www.rfc-editor.org/info/rfc7554>.

[RFC7567] Baker, F., Ed. and G. Fairhurst, Ed., «IETF Recommendations Regarding Active Queue Management», BCP 197, RFC 7567, DOI 10.17487/RFC7567, July 2015, <https://www.rfc-editor.org/info/rfc7567>.

[RFC7813] Farkas, J., Ed., Bragg, N., Unbehagen, P., Parsons, G., Ashwood-Smith, P., and C. Bowers, «IS-IS Path Control and Reservation», RFC 7813, DOI 10.17487/RFC7813, June 2016, <https://www.rfc-editor.org/info/rfc7813>.

[RFC8033] Pan, R., Natarajan, P., Baker, F., and G. White, «Proportional Integral Controller Enhanced (PIE): A Lightweight Control Scheme to Address the Bufferbloat Problem», RFC 8033, DOI 10.17487/RFC8033, February 2017, <https://www.rfc-editor.org/info/rfc8033>.

[RFC8227] Cheng, W., Wang, L., Li, H., van Helvoort, H., and J. Dong, «MPLS-TP Shared-Ring Protection (MSRP) Mechanism for Ring Topology», RFC 8227, DOI 10.17487/RFC8227, August 2017, <https://www.rfc-editor.org/info/rfc8227>.

[RFC8289] Nichols, K., Jacobson, V., McGregor, A., Ed., and J. Iyengar, Ed., «Controlled Delay Active Queue Management», RFC 8289, DOI 10.17487/RFC8289, January 2018, <https://www.rfc-editor.org/info/rfc8289>.

[RFC8402] Filsfils, C., Ed., Previdi, S., Ed., Ginsberg, L., Decraene, B., Litkowski, S., and R. Shakir, «Segment Routing Architecture», RFC 8402, DOI 10.17487/RFC8402, July 2018, <https://www.rfc-editor.org/info/rfc8402>.

[RFC8453] Ceccarelli, D., Ed. and Y. Lee, Ed., «Framework for Abstraction and Control of TE Networks (ACTN)», RFC 8453, DOI 10.17487/RFC8453, August 2018, <https://www.rfc-editor.org/info/rfc8453>.

[RFC8557] Finn, N. and P. Thubert, «Deterministic Networking Problem Statement», RFC 8557, DOI 10.17487/RFC8557, May 2019, <https://www.rfc-editor.org/info/rfc8557>.

[RFC8578] Grossman, E., Ed., «Deterministic Networking Use Cases», RFC 8578, DOI 10.17487/RFC8578, May 2019, <https://www.rfc-editor.org/info/rfc8578>.

[TEAS] IETF, «Traffic Engineering Architecture and Signaling (teas)», October 2019, <https://datatracker.ietf.org/doc/charter-ietf-teas/>.

[TSCH-ARCH] Thubert, P., «An Architecture for IPv6 over the TSCH mode of IEEE 802.15.4», Work in Progress, Internet-Draft, draft-ietf-6tisch-architecture-26, 27 August 2019, <https://tools.ietf.org/html/draft-ietf-6tisch-architecture-2636>.

Благодарности

Авторы благодарны Lou Berger, David Black, Stewart Bryant, Rodney Cummings, Ethan Grossman, Craig Gunther, Marcel Kiessling, Rudy Klecka, Jouni Korhonen, Erik Nordmark, Shitanshu Shah, Wilfried Steiner, George Swallow, Michael Johas Teener, Pat Thaler, Thomas Watteyne, Patrick Wetterwald, Karl Weber и Anca Zamfir за их вклад в эту работу.

Адреса авторов

Norman Finn

Huawei

3101 Rio Way

Spring Valley, California 91977

United States of America

Phone: +1 925 980 6430

Email: nfinn@nfinnconsulting.com

Pascal Thubert

Cisco Systems

Batiment T3

Village d’Entreprises Green Side, 400, Avenue de Roumanille

06410 Biot — Sophia Antipolis

France

Phone: +33 4 97 23 26 34

Email: pthubert@cisco.com

Balázs Varga

Ericsson

Budapest

Magyar tudosok korutja 11

1117

Hungary

Email: balazs.a.varga@ericsson.com

János Farkas

Ericsson

Budapest

Magyar tudosok korutja 11

1117

Hungary

Email: janos.farkas@ericsson.com

Перевод на русский язык

Николай Малых

nmalykh@protokols.ru

1Deterministic Networking.

2Time-Sensitive Networking — чувствительные ко времени сети.

3Internet Engineering Task Force.

4Internet Engineering Steering Group.

5Quality-of-Service — качество обслуживания.

6Resource Reservation Protocol — протокол резервирования ресурсов.

7Label Edge Router — краевой маршрутизатор по меткам.

8Provider Edge — краевой маршрутизатор провайдера.

9MPLS Label Switch Router — маршрутизатор с коммутацией по меткам.

10Shared Risk Link Group — группа каналов с общим риском.

11Segment Routing — сегментная маршрутизация.

12Traffic Engineering — организация трафика.

13Label Switched Path — путь с коммутацией по меткам.

14Class-of-Service.

15Operations, Administration, and Maintenance — эксплуатация, администрирование, поддержка.

16Optical Transport Network — оптическая транспортная сеть.

17Real-time Transport Protocol — протокол доставки в реальном масштабе времени.

18Pseudowire.

19Network Interface Card — плата сетевого интерфейса.

20Time-division multiplexing — мультиплексирование с разделением по времени.

21Transport Profile — транспортный профиль.

22Traffic Engineering Architecture and Signaling — архитектура и сигнализация для организации трафика.

23Traffic Engineering — организация трафика.

24Flow Management Entity — элемент управления потоком.

25Traffic Specification — спецификация трафика.

26Common Control and Measurement Plane — общая плоскость управления и измерений.

27Controller Plane Function — функция плоскости контроллера.

28Path Computation Element — элемент расчета пути.

29Network Management Entity — элемент управления сетью.

30Abstraction and Control of Traffic Engineered Network.

31Man-in-the-middle — перехват и изменение трафика с участием человека.

32Работа опубликована в RFC 8938. Прим. перев.

33Работа опубликована в RFC 8939. Прим. перев.

34Доступен более свежий вариант https://tools.ietf.org/html/draft-ietf-detnet-mpls-13. Прим. перев.

35Доступен более свежий вариант https://tools.ietf.org/html/draft-ietf-detnet-security-12. Прим. перев.

36Доступен более свежий вариант https://tools.ietf.org/html/draft-ietf-6tisch-architecture-30. Прим. перев.

 

Рубрика: RFC | Комментарии к записи RFC 8655 Deterministic Networking Architecture отключены

Пакет tcpdump

PDF

http://www.tcpdump.org

Данный документ соответствует tcpdump версии 4.9.3 и libpcap версии 1.9.1.

Синтаксис

      tcpdump [ -AbdDefhHIJKlLnNOpqStuUvxX# ] [ -B buffer_size ] 
              [ -c count ] 
              [ -C file_size ] [ -G rotate_seconds ] [ -F file ] 
              [ -i interface ] [ -j tstamp_type ] [ -m module ] [ -M secret ] 
              [ --number ] [ -Q in|out|inout ] 
              [ -r file ] [ -V file ] [ -s snaplen ] [ -T type ] [ -w file ] 
              [ -W filecount ] 
              [ -E spi@ipaddr algo:secret,...  ] 
              [ -y datalinktype ] [ -z postrotate-command ] [ -Z user ] 
              [ --time-stamp-precision=tstamp_precision ] 
              [ --immediate-mode ] [ --version ] 
              [ expression ]

Программа tcpdump, включаемая во все дистрибутивы UNIX, выводит заголовки пакетов для указанных сетевых интерфейсов в соответствии с заданным логическим выражением. Программа также допускает использование с флагом -w для записи пакетов данных в файл, которым может впоследствии использоваться для анализа. Возможен и просмотр заголовков из таких файлов с помощью флага -r. Во всех случаях tcpdump имеет дело только с пакетами, соответствующими заданному логическому выражению (фильтру).

Tcpdump (если в команде не был указан флаг -c) продолжает собирать пакеты до тех пор, пока процесс не будет прерван сигналом SIGINT (например, при нажатии клавиш control-C) или SIGTERM (например, в результате команды kill(1)). Если команда используется с флагом -c, сбор пакетов кроме описанных выше способов может быть прекращен также после обработки определенного числа пакетов.

При завершении работы tcpdump выводит значения счетчиков:

  • собранных (captured) пакетов (число пакетов, полученных и обработанных tcpdump);

  • полученных фильтром (received by filter) пакетов; толкование этого значения зависит от ОС, под управлением которой работала программа tcpdump (в некоторых ОС указывается число пакетов независимо от числа совпадений с условиями фильтрации, а в других — число пакетов, соответствующих фильтрам);

  • отброшенных ядром (dropped by kernel) пакетов (число пакетов, отброшенных ядром по причине нехватки ресурсов или фильтрации внутри ядра).

На платформах, поддерживающих сигналы SIGINFO (например, BSD), могут выводиться значения перечисленных выше счетчиков по сигналу SIGINFO (этот сигнал может быть подан обычно с помощью клавиш control-T) без прерывания работы команды.

Отметим, что чтение пакетов из сетевого интерфейса может потребовать от пользователя специальных привилегий в зависимости от используемой ОС:

  • SunOS 3.x или 4.x с NIT или BPF
    требуется доступ для чтения к файлам устройств /dev/nit или /dev/bpf*.

  • Solaris с DLPI
    требуется доступ для чтения и записи к сетевому псевдоустройству (например, /dev/le). На некоторых версиях Solaris таких прав недостаточно для работы tcpdump в режиме захвата1; в таких ситуациях для использования tcpdump требуются полномочия root или установка для tcpdump флага SUID. Отметим, что на многих (возможно, на всех) системах при работе устройства в обычном режиме вы не сможете видеть никаких исходящих пакетов, поэтому сбор данных в таком режиме может оказаться практически бесполезным.

  • HP-UX с DLPI
    требуются полномочия root или установка для tcpdump флага SUID.

  • IRIX с snoop
    требуются полномочия root или установка для tcpdump флага SUID.

  • Linux
    требуются полномочия root или установка для tcpdump флага SUID, если ваша система не использует ядро с поддержкой битов возможностей2 (таких, как CAP_NET_RAW). В последнем случае для вам потребуется установка бита CAP_NET_RAW для захвата пакетов и бита CAP_NET_ADMIN для просмотра списка устройств помощью опции -D. Для просмотра текущего состояния битов возможностей служит функция getcap, а для управления этими битами — setcap из библиотеки libcap. Дополнительную информацию о поддерживаемых битах возможностей вы найдете, воспользовавшись командой man capabilities.

  • ULTRIX и Digital UNIX/Tru64 UNIX
    всем пользователям разрешено использование программы tcpdump. Однако никому из пользователей не разрешено использовать режим захвата пакетов, пока администратор (super-user) не разрешит этот режим для данного интерфейса с помощью команды pfconfig. Захват принимаемых или передаваемых интерфейсом unicast-пакетов не будет возможен до тех пор, пока администратор (super-user) не включит для этого интерфейса режим copy-all с помощью команды pfconfig. Поскольку сбор пакетов обычно требует включения обоих упомянутых режимов, реальное использование tcpdump возможно только с позволения администратора.

  • BSD и Mac OS X
    требуется доступ для чтения к устройству /dev/bpf*. На системах BSD с поддержкой devfs (сюда относятся и системы Mac OS X) кроме установки принадлежности и прав доступа к устройствам BPF может потребоваться настройка конфигурации devfs, позволяющая задавать принадлежность и права доступа всякий раз при перезагрузке системы.

Чтение собранных пакетов из файла не требует специальных привилегий.

Опции tcpdump

Программа tcpdump позволяет в командной строке задать все опции сбора и отображения пакетов, а также спецификацию фильтров захвата, описанных ниже (параграф на стр. ). Таблица содержит список опций tcpdump и описание каждой их них. Отметим, что некоторые опции поддерживаются не всеми платформами.

Таблица 1. Опции командной строки tcpdump.

Опция

Описание

-A

Задает вывод каждого пакета (без заголовков канального уровня) в формате ASCII. Этот режим удобен для сбора трафика HTTP.

-b

Задает вывод номера автономной системы (AS) из пакетов протокола BGP в формате ASDOT вместо ASPLAIN.

-B <размер буфера>
--buffer-size=<размер буфера>

Задает размер буфера захвата пакетов для операционной системы в килобайтах (1024 байта).

-c <число пакетов>

Задает завершение работы программы после захвата заданного числа пакетов.

-C <размер файла>

Задает необходимость проверки размера файла захвата перед записью в него каждого нового пакета. Если размер файла превышает указанное значение параметра, прежний файл закрывается и создается новый файл для записи в него пакетов. Для файлов захвата используется имя, заданное параметром -w и, начиная со второго файла, к имени добавляется в качестве суффикса порядковый номер файла. Параметр задает размер файла в миллионах байтов (не в мегабайтах = 1 048 576 байт).

-d

Задает вывод дампа скомпилированного кода сопоставления пакетов в понятном человеку формате и завершение работы программы.

-dd

Выводит дамп кода сопоставления в виде фрагмента C-программы.

-ddd

Выводит дамп кода сопоставления в виде строки десятичных значений с префиксом в форме значения счетчика.

-D

Выводит список сетевых интерфейсов системы, с которых tcpdump может собирать пакеты. Для каждого сетевого интерфейса указывается имя и номер, за которыми может следовать текстовое описание интерфейса. Имя и номер интерфейса могут использоваться с флагом -i для задания сбора пакетов с одного интерфейса.

Эта опция может быть весьма полезна для систем, не дающих информации об имеющихся сетевых интерфейсах3.

Флаг -D не поддерживается, если программа tcpdump была скомпилирована со старой версией libpcap, которая не поддерживает функцию pcap_findalldevs().

-e

Выводит заголовок канального уровня в каждой строке дампа.

-E <algo:secret>

Задает использование алгоритма и секрета spi@ipaddr для расшифровки пакетов IPsec ESP, направленных по адресу ipaddr и содержащих в поле Security Parameter Index значение spi. Комбинация spi и адреса может быть повторена с использованием в качестве разделителя запятой или новой строки. Отметим, что установка секрета для пакетов IPv4 ESP в настоящее время поддерживается. В качестве алгоритмов могут использоваться des-cbc, 3des-cbc, blowfish-cbc, rc3-cbc, cast128-cbc или none. По умолчанию применяется алгоритм des-cbc. Возможность дешифровки пакетов обеспечивается только в тех случаях, когда при компиляции tcpdump были включены опции поддержки криптографии. Параметр secret содержит ASCII-текст секретного ключа ESP. Если секрет начинается с символов 0x, будет считываться шестнадцатеричное значение. Опция предполагает использование ESP в соответствии с RFC 2406, а не RFC 1827. Эта опция поддерживается только для отладки и использовать ее с реальными секретными ключами не следует, поскольку введенный в командной строке ключ IPsec доступен другим пользователям системы4. Кроме явного указания параметров в командной строке их можно задать в файле опций, который tcpdump будет читать при получении первого пакета ESP.

-f

Задает вывод чужих адресов IPv4 в числовом формате. Использование этой опции позволяет избавиться от проблем, возникающих на серверах Sun NIS при попытках трансляции нелокальных адресов. Проверка чужеродности адреса IPv4 осуществляется с использованием адреса и маски принявшего пакет интерфейса. Если адрес и маска интерфейса недоступны (например, при использовании unnumbered-интерфейсов или при захвате пакетов со всех адресов в Linux с использованием фиктивного интерфейса any), эта опция будет работать некорректно.

-F <файл>

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

-G rotate

Задает смену файла, заданного опцией -w каждые rotate секунд. Файлы будут именоваться в соответствии с опцией -w с добавлением временной метки в формате strtime. Если формат временных меток не задан, новые файлы будут записываться вместо предшествующего. При использовании с опцией -C имена файлов будут иметь вид file<count>

-h
--help

Выводит информацию о текущих версиях tcpdump и libpcap, а также краткую справку о программе tcpdump, после чего завершает заботу.

--vervion

Выводит информацию о текущих версиях tcpdump и libpcap, после чего завершает заботу.

-H

Задает попытку декодировать заголовки 802.11s.

-i <интерфейс>
--interface=<интерфейс>

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

В системах Linux, начиная с ядра 2.2 поддерживается фиктивный интерфейс с именем any, обеспечивающий сбор пакетов со всех активных интерфейсов системы. Отметим, что сбор пакетов с устройства any осуществляется в обычном (не promiscuous) режиме.

Если в системе поддерживается флаг -D, можно в качестве аргумента задавать номер интерфейса, выводимый при использовании этого флага.

-I
--monitor-mode

Переводит интерфейс в режим мониторинга, доступный лишь для IEEE 802.11 Wi-Fi в некоторых операционных системах. Следует отметить, что в этом режиме сетевой интерфейс может потерять установленную связь с беспроводной сетью и использование этой сети станет невозможным.

Эта опция влияет на вывод при использовании опции -L. При выключенной опции -I будут отображаться только те типы кадров канального уровня, которые не доступны в режиме мониторинга, а при включенной опции — только доступные в режиме мониторинга.

--immediate-mode

Задает режим непосредственного захвата (immediate), когда пакеты доставляются в tcpdump без буферизации. Такое поведение принято по умолчанию при отображении пакетов без записи в файл.

-j <тип метки>
--time-stamp-type=<тип метки>

Задает тип временных меток, отображаемых с пакетами. Имена меток задаются pcap-tstamp, но некоторые типы меток пригодны не для всех интерфейсов.

-J 
--list-time-stamp-types

Выводит список поддерживаемых для интерфейсов типов временных меток и на этом завершает работу.

--time-stamp-precision=<точность меток>

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

При чтении данных из файла эта опция задает преобразование использованной при записи файла точности в указанное опцией разрешение, при котором может происходить снижение точности.

Поддерживаются значения micro (мискросекундная точность, принята по умолчанию) и nano (наносекундная точность).

-K 
--dont-verify-checksums

Отключает проверку контрольных сумм IP, TCP и UDP. Это полезно для интерфейсов, полностью или частично вычисляющих контрольные суммы на аппаратном уровне, поскольку без опции контрольные суммы TCP могут оказаться в таких случаях неверными.

-l

Задает буферизацию строк stdout. Эта опция полезна в тех случаях, когда нужно просматривать данные во время сбора пакетов. Например, команды

tcpdump -l | tee dat

или

tcpdump -l > dat & tail -f dat

обеспечивают запись пакетов в файл dat и одновременный вывод на консоль.

-L
--list-data-link-types

Задает вывод списка известных типов канального уровня и завершение работы программы. Список может зависеть от режима и , например, на некоторых платформах часть типов Wi-Fi может не поддерживаться в режиме мониторинга, а другие могут поддерживаться лишь в этом режиме.

-m <файл>

Загружает модуль определений SMI MIB из указанного файла. Эта опция может использоваться неоднократно для загрузки нескольких модулей MIB.

-M <секрет>

Задает использование общего секрета для проверки цифровых подписей в сегментах TCP с опцией TCP-MD5 (RFC 2385).

-n

Отключает преобразование адресов и номеров портов в символьные имена.

-N

Задает использование лишь хостовой части доменного имени вместо FQDN.

-# 
--number

Задает вывод номера пакета в начале строки.

-O
--no-optimize

Отключает оптимизатор кода сопоставления пакетов с фильтрами (стр. 6). Опция полезна лишь при наличии ошибок в оптимизаторе.

-p
--no-promiscuous-mode

Указывает программе, что интерфейс не нужно переводить в неразборчивый режим5. Опцию -p нельзя использовать в сокращенной форме вместе с фильтром ether host {local-hw-addr} или ether broadcast.

-Q direction 
--direction=direction

Выбирает направление приема или передачи для захвата пакетов и может принимать значение in, out или inout. Поддерживается не всеми системами.

-q

Задает вывод минимального объема информации.

-r <файл>

задает чтение данных из файла, созданного ранее с использованием команды tcpdump -w или с помощью другой программы, поддерживающей формат tcpdump (например, Ethereal). Если в качестве имени файла задан символ , используется поток данных от стандартного устройства ввода (stdin).

-S
--absolute-tcp-sequence-numbers

Задает вывод абсолютных порядковых номеров TCP взамен относительных.

-s <snaplen>
--snapshot-length=snaplen

Задает захват из каждого пакета snaplen байтов вместо отбираемых по умолчанию 68 байтов6. Значение 68 подходит для протоколов IP, ICMP, TCP и UDP, но может приводить к потере протокольной информации для некоторых пакетов DNS (стр. 16) и NFS (стр. 17). Потеря части пакетов по причине малого размера кадра захвата (snapshot) указывается в выходных данных полями вида [|proto]‘, где proto — имя протокольного уровня, на котором произошла отсечка части пакета7. Отметим, что увеличение кадра захвата приведет к дополнительным временным затратам на обработку пакетов и уменьшению числа буферизуемых пакетов, что может привести к потере части пакетов. Следует указывать минимальное значение snaplen, которое позволит обойтись без потери информации об интересующем протоколе. Установка snaplen = 0 приведет к захвату до 262144 байтов.

-T <тип>

Задает интерпретацию пакетов, выбранных с помощью фильтра (см. параграф на стр.) как пакетов указанного параметром типа. В настоящее время поддерживаются типы aodv8, carp9, cnfp10, lmp11, pgm12, pgm_zmtp113, resp14, radius, rpc15, rtp16, rtcp17, snmp18, tftp19, vat20, wb21, zmtp122 и vxlan23.

-t

Отключает вывод временных меток в каждой строке дампа.

-tt

Задает вывод в каждой строке дампа неформатированных временных меток.

-ttt

Задает вывод временных интервалов (в микросекундах) между захватом предыдущего и данного пакетов в каждой строке дампа.

-tttt

Задает вывод временных меток в принятом по умолчанию формате для каждой строки дампа.

-u

Задает вывод манипуляторов (handle) NFS без декодирования.

-U
--packet-buffered

Задает режим буферизации на уровне пакетов для файлов, когда содержимое пакета отображается на стандартном устройстве вывода (и записывается в файл при наличии опции -w) без ожидания заполнения буфера. Флаг -U не будет поддерживаться, если программа tcpdump была скомпилирована со старой опцией libpcap, не поддерживающей функцию pcap_dump_flush().

-v

Задает вывод дополнительной информации из пакета. К такой информации может относиться значение TTL (время жизни), идентификация, общий размер, опции IP и т. п. При использовании этого флага также выполняется дополнительная проверка целостности пакетов с помощью контрольных сумм (например, для протоколов IP и ICMP).

-vv

Задает дополнительное увеличение объема выводимой информации (например, полное декодирование пакетов SMB, вывод дополнительных полей откликов NFS и т. п.).

-vvv

Задает максимальный объем выводимой информации (например, полностью выводятся опции telnet SB … SE). При использовании вместе с ключом -X опции Telnet выводятся также в шестнадцатеричном представлении.

-V <файл>

Задает считывание списка имен из файла или со стандартного ввода (-).

-w <файл>

Задает запись необработанных (raw) пакетов в файл. Собранные в файл пакеты можно впоследствии просматривать с использованием опции -r или передавать для анализа другим программам. Если в качестве имени файла указан символ , запись осуществляется на стандартное устройство вывода (stdout).

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

Для файлов pcap агентством IANA зарегистрирован тип MIME application/vnd.tcpdump.pcap.

-W

При использовании с опцией -C будет ограничивать число записываемых файлов заданным значением, по достижении которого самый старый файл будет перезаписываться. При именовании файлов номера будут дополняться слева нужным числом нулей для корректной сортировки по росту номеров.

При использовании с опцией -G будет ограничивать число создаваемых при ротации по времени файлов, возвращая статус 0 при достижении предела.

При использовании с опциями -C и -G будет зацикливать ротацию файлов.

-x

Задает вывод шестнадцатеричного дампа (без заголовка канального уровня) для каждого захваченного пакета. Объем выводимой информации определяется меньшим из двух значений — размер пакета и значение параметра snaplen (см. стр. 4). Отметим, что при захвате полных кадров канального уровня дамп может включать также байты заполнения, если пакет сетевого уровня имеет малый размер.

-xx

Задает вывод шестнадцатеричного дампа для каждого пакета с включением заголовков канального уровня.

-X

Задает вывод дампа в шестнадцатеричном и ASCII-формате без заголовков канального уровня. Эта опция может быть очень удобна при анализе новых протоколов.

-XX

Задает вывод дампа в шестнадцатеричном и ASCII-формате с включением заголовков канального уровня.

-y <тип>
--linktype=datalinktype

Задает тип канального уровня, используемый при захвате пакетов. Поддерживаемые значения можно посмотреть с помощью опции -L.

-z <команда>

При использовании с опцией -C или -G будет вызывать указанную команду после закрытия каждого записываемого файла. Команда запускается параллельно tcpdump (с низким приоритетом) и не прерывает захват пакетов. Если нужно использовать команду, включающую флаги и/или аргументы, можно поместить эту команду в файл сценария, а сценарий вызывать данной опцией.

-Z user 
--relinquish-privileges=user

При работе tcpdump от имени пользователя root эта опция задает смену идентификатора пользователя и группы на идентификатор основного пользователя и группы после открытия устройства захвата или входного файла, но до открытия выходных файлов.

expression

Задает фильтр отбора пакетов. Синтаксис фильтров описан ниже.

Фильтрация при отборе пакетов

В командной строке tcpdump наряду с опциями могут задаваться выражения, определяющие фильтрацию пакетов на этапе их отбора. Если никакого фильтра не задано, программа будет собирать все пакеты.

Каждое выражение, задающее фильтр, включает один или несколько примитивов, состоящих обычно из одного или множества идентификаторов объектов и предшествующих им классификаторов. Идентификатором объекта может служить его имя или номер. Классификаторы объектов могут относиться к одному из трех видов.

type — тип

Указывает тип объекта, заданного идентификатором. В качестве типа объектов могут указываться значения host (хост), net (сеть) и port (порт). Если тип объекта не указан, предполагается значение host.

dir — направление

Задает направление по отношению к объекту. Для этого классификатора поддерживаются значения src (объект является отправителем), dst (объект является получателем), src or dst (отправитель или получатель) и src and dst (отправитель и получатель), ra, ta, addr1, addr2, addr3, addr4. Например, src foo указывает на пакеты, отправленные с хоста foo, dst net 128.3 — пакеты, адресованные в сеть 128.3.0.0/16, а src or dst port ftp-data — пакеты данных протокола FTP (порт ftp-data), передаваемые в обоих направлениях. Если классификатор dir не задан, предполагается значение src or dst. Для некоторых типов соединений (например, SLIP) и режимов отбора (например, отбор с фиктивного интерфейса any в Linux-системах) могут использоваться классификаторы inbound и outbound. Значения ra, ta, addr1, addr2, addr3, addr4 применимы только для беспроводных интерфейсов IEEE 802.11.

proto — протокол

Задает протокол, к которому должны относиться пакеты. Этот классификатор может принимать значения ether, fddi24, tr25, wlan26, ip, ip6, arp, rarp, decnet, tcp и udp. Если примитив не содержит классификатора протокола, предполагается, что данному фильтру удовлетворяют все протоколы, совместимые с типом объекта27.

Кроме объектов и классификаторов примитивы могут содержать ключевые слова gateway (шлюз), broadcast (широковещательный), less (меньше), greater (больше) и арифметические выражения.

Сложные фильтры могут содержать множество примитивов, связанных между собой с использованием логических операторов and, or и not (например, host foo and not port ftp and not port ftp-data). Для сокращения задающих фильтры выражений можно опускать идентичные списки классификаторов. Например, выражение tcp dst port ftp or ftp-data or domain будет краткой формой выражения

tcp dst port ftp or tcp dst port ftp-data or tcp dst port domain
Допустимые примитивы фильтрации пакетов

Ниже приводится список допустимых примитивов с краткими комментариями для каждого из них.

Таблица 2. Примитивы фильтров tcpdump.

Примитив

Описание

dst host <хост>

Будет отбирать пакеты, в которых поле адреса получателя IPv4/v6 содержит адрес хоста, заданного в примитиве.

src host <хост>

Будет выбирать все пакеты, в которых поле отправителя содержит адрес указанного хоста.

host <хост>

Будет отбирать все пакеты, для которых адрес хоста указан в поле получателя или отправителя.

Все три приведенных выше выражения могут содержать идентификаторы протоколов ip, arp, rarp или ip6, как в выражении

ip host <хост>

эквивалентном фильтру:

ether proto \ip and host <хост>

Если именем задан хост, с которым связано несколько адресов IP, фильтру будут соответствовать пакеты с любым из этих адресов в заголовках пакетов.

ether dst <ehost>

Будет выбирать все кадры, в которых поле MAC-адреса получателя содержит значение ehost (имя хоста из файла /etc/ethers или шестнадцатеричное представление MAC-адреса28).

ether src <ehost>

Будет выбирать все кадры, в которых поле MAC-адреса отправителя содержит значение ehost.

ether host <ehost>

Будет отбирать все пакеты с адресом, указанным значением ehost в поле отправителя или получателя.

gateway <шлюз>

Будет отбирать все пакеты, использующие указанный именем хост в качестве шлюза29. Указанное параметром имя хоста должно преобразовываться в IP-адрес механизмами преобразования имен, доступными локальному компьютеру (/etc/hosts, DNS, NIS и т. п.), а также механизмами определения MAC-адреса по имени хоста (/etc/ethers и т. п.). Эквивалентное выражение ether host ehost and not host <хост> позволяет указывать хост по имени или адресу, заданному в файле host/ehost. Отметим, что данный примитив пока не поддерживается для конфигураций IPv6.

dst net <сеть>

Отбирает все пакеты IPv4/v6, направленные в указанную сеть. Для указания сети можно использовать имя из файла /etc/networks или номер сети. Сети IPv4 можно задавать в сокращенной форме (например, 192.168 или 10), сети IPv6 должны указываться полностью.

src net <сеть>

Выбирает все пакеты Ipv4/v6, отправленные из указанной сети.

net <сеть>

Выбирает все пакеты IPv4/v6, содержащие адреса из указанной сети в поле отправителя или получателя.

net <сеть> mask <маска>

Будет отбирать все пакеты IPv4, содержащие в поле отправителя или получателя адреса из сети, указанной с использованием маски.

net <сеть/размер маски>

Будет отбирать все пакеты IPv4/v6, содержащие в поле отправителя или получателя адреса из сети, указанной с использованием маски.

dst port <порт>

Отберет все пакеты ip/tcp, ip/udp, ip6/tcp и ip6/udp, направленные в указанный порт. Номера портов могут задаваться номерами или именами из файла /etc/services. При указании имени (протокол/порт) проверяется как порт, так и протокол. Если примитив содержит неоднозначный номер или имя порта, проверяется только порт (без протокола) и фильтру будут соответствовать пакеты обоих протоколов (tcp и udp). Например, фильтру dst port 513 будут соответствовать пакеты tcp/login и udp/who, а фильтру port domaintcp/domain и udp/domain.

src port <порт>

Отбирает все пакеты, отправленные из указанного порта.

port <порт>

Отбирает все пакеты, содержащие указанный номер порта в поле отправителя или получателя. Любое из трех перечисленных правил для портов может включать в качестве префикса идентификатор протокола tcp или udp (например, tcp src port <порт>, будет отбирать пакеты tcp, отправленные из указанного порта).

dst portrange port1-port2

Отберет пакеты ip/tcp, ip/udp, ip6/tcp и ip6/udp, направленные в указанный диапазон портов. Интерпретация параметров port такая же, как для одного порта.

src portrange port1-port2

Отберет пакеты, направленные из указанного диапазона портов.

portrange port1-port2

Отберет пакеты, в которых порт отправителя или получателя попадает в указанный диапазон.

less <размер>

Отберет пакеты, размер которых не больше указанного. Эквивалентно len <= length.

greater <размер>

Отберет пакеты, размер которых не меньше указанного. Эквивалентно len >= length.

ip proto <протокол>

Отбирает пакеты IPv4, содержащие заданный идентификатор типа в поле протокола. Типы протоколов IP можно указывать по именам или (icmp, icmp6, igmp, igrp, pim, ah, esp, vrrp, udp, tcp) или номерам. Поскольку tcp, udp и icmp используются также в качестве ключевых слов, их следует экранировать символом \. Отметим, что этот примитив не проверяет цепочки протокольных заголовков.

ip6 proto <протокол>

Отберет пакеты IPv6 указанного типа без проверки цепочки протокольных заголовков.

proto <протокол>

Отберет пакеты IPv4 и IPv6 указанного типа без проверки цепочки протокольных заголовков.

tcp, udp, icmp

Сокращение для proto <протокол>, где протокол относится к одному из указанных.

ip6 protochain <протокол>

Отберет все пакеты IPv6, содержащие в цепочке протокольных заголовков идентификатор указанного типа протокола. Например, фильтру ip6 protochain 6 будут соответствовать все пакеты IPv6 с заголовками TCP в цепочке заголовков. Такой пакет может содержать, например, заголовок аутентификации (AH), маршрутный заголовок (routing header), или заголовок опции hop-by-hop между заголовками IPv6 и TCP. Отметим, что порождаемый этим примитивом код BPF достаточно сложен и не может быть оптимизирован средствами tcpdump, поэтому использование данного фильтра может замедлять работу программы.

ip protochain <протокол>

Эквивалентно примитиву ip6 protochain protocol, но работает с пакетами IPv4.

ip protochain <протокол>

Эквивалентно ip6 protochain protocol, но работает с пакетами IPv4 и IPv6.

ether broadcast

Обеспечивает отбор всех широковещательных кадров Ethernet. Ключевое слово ether может быть опущено.

ip broadcast

Отбирает все широковещательные пакеты IPv4. Этому правилу будут соответствовать широковещательные адреса, содержащие только нули (all-zeroes) и только единицы (all-ones) с учетом маски подсети для интерфейса, который используется для отбора пакетов. Если маска подсети для интерфейса недоступна30, фильтр может работать некорректно.

ether multicast

Собирает все кадры с групповыми адресами Ethernet. Ключевое слово ether необязательно. Логически это правило эквивалентно выражению ether[0] & 1 != 0.

ip multicast

Отбирает пакеты с групповыми адресами IPv4.

ip6 multicast

Отбирает пакеты с групповыми адресами IPv6.

ether proto <протокол>

Отбирает кадры Ethernet с заданным типом протокола. Протокол может быть указан по номеру или имени31 (ip, ip6, arp, rarp, atalk, aarp, decnet, sca, lat, mopdl, moprc, iso, stp, ipx, netbeui).

При использовании правила для протоколов FDDI (например, fddi protocol arp), Token Ring (например, tr protocol arp) или IEEE 802.11 (например, wlan protocol arp) идентификация протокола выполняется на основании заголовка 802.2 Logical Link Control (LLC), который следует после заголовка FDDI, Token Ring или 802.11.

При фильтрации для большинства протоколов FDDI, Token Ring и 802.11 tcpdump проверяет только поле идентификатора протокола (protocol ID) в заголовке LLC так называемого SNAP-формата с идентификатором OUI = 0x000000 (Organizational Unit Identifier), указывающим на инкапсуляцию Ethernet. Проверка использования формата SNAP с OUI = 0x000000 не выполняется за исключением перечисленных ниже случаев:

iso

tcpdump проверяет поля DSAP32 и SSAP33 в заголовках LLC;

stp, netbeui

tcpdump проверяет поле DSAP в заголовке LLC;

atalk

проверяется формат SNAP с OUI = 0x080007 и тип (etype) AppleTalk.

Для Ethernet проверяются поля типа Ethernet для большинства протоколов. Исключения указаны ниже

iso, sap, netbeui

проверяется принадлежность к 802.3 и заголовок LLC (как это описано выше для FDDI, Token Ring и 802.11);

atalk

проверяется тип AppleTalk в кадре Ethernet и формат заголовка SNAP (как для FDDI, Token Ring и 802.11);

aarp

проверяется тип AppleTalk ARP в кадре Ethernet или использование формата 802.2 SNAP с OUI = 0x000000;

ipx

tcpdump проверяет тип IPX в кадре Ethernet, поле IPX DSAP в заголовке LLC, инкапсуляцию IPX и тип IPX в кадре SNAP.

ip, ip6, arp, rarp, atalk, aarp, decnet, iso, stp, ipx, netbeui

Сокращения для ether proto <протокол>, где указан один из протоколов.

lat, moprc, mopdl

Сокращения для ether proto <протокол>, где указан один из протоколов. Отметим, что не все приложения, использующие pcap(3PCAP), понимают эти протоколы.

decnet src <хост>

Собирает все пакеты от указанного хоста DECNET, который может быть задан по адресу в форме 10.123 или имени DECNET34.

decnet dst <хост>

Отбирает все пакеты, адресованные указанному хосту DECNET.

decnet host <хост>

Собирает все пакеты, содержащие адрес указанного хоста DECNET в поле отправителя или получателя.

llc

Отбирает пакет с заголовком 802.2 LLC, включая:

пакеты Ethernet с полем length вместо поля type, которые не являются неразобранными пакетами Netware IEEE 802.3;

пакеты IEEE 802.11;

пакеты Token Ring (без проверки LLC);

пакеты FDDI (без проверки LLC);

пакеты ATM с инкапсуляцией LLC (например, SunATM в Solaris).

llc type

Отбирает пакет с заголовком 802.2 LLC указанного типа:

i — информационные PDU (I);

s — PDU управления (S, supervisory);

u — unnumberd PDU (U);

rr — PDU готовности приемника (RR);

rnr — PDU неготовности приемника (RNR);

rej — PDU отторжения (REJ, reject);

ui — PDU ненумерованной информации (UI);

ua — PDU ненумерованных подтверждений (UA);

disc — PDU разрыва соединения (DISC, disconnect);

sabme — PDU расширенного сбалансированного режима (SABME);

test — тестовые PDU (TEST);

xid — PDU информационного обмена (XID);

frmr — PDU отторжения кадра (FRMR);

inbound

Пакеты, полученные хостом, где выполняется отбор. Поддерживается лишь некоторыми типами интерфейсов, такими как SLIP, фиктивный интерфейс Linux any и др.

outbound

Пакеты, переданные хостом, где выполняется отбор. Поддерживается лишь некоторыми типами интерфейсов, такими как SLIP, фиктивный интерфейс Linux any и др.

ifname <интерфейс>

Отбирает все пакеты, полученные от указанного интерфейса35.

on <интерфейс>

Синоним ifname.

rnr <номер>

Собирает только пакеты, записанные в файл программой pf в соответствии с правилом, имеющим указанных номер (доступно только при сборе пакетов с помощью OpenBSD и FreeBSD pf).

rulenum <номер>

Синоним для rnr.

reason <код>

Собирает только пакеты, соответствующие указанному коду причины PF. Известные коды причин включают match, bad-offset, fragment, short, normalize, memory (доступно только при сборе пакетов с помощью OpenBSD и FreeBSD pf).

rset <имя>

Собирает пакеты, соответствующие указанному именем правилу привязанного набора (доступно только при сборе пакетов с помощью OpenBSD и FreeBSD pf).

ruleset <имя>

Синоним rset.

srnr <номер>

Собирает пакеты, соответствующие указанному номером правилу привязанного набора (доступно только при сборе пакетов с помощью OpenBSD и FreeBSD pf).

subrulenum <номер>

Синоним srnr.

action <действие>

Отбирает пакеты, захваченные указанной операцией pf (pass или block, а для некоторых версий pf также nat, rdr, binat и scrub). Правило доступно только при сборе пакетов с помощью OpenBSD и FreeBSD pf.

wlan ra ehost

Отбирает пакеты с полем IEEE 802.11 RA равным ehost. Поле RA отсутствует в кадрах управления.

wlan ta ehost

Отбирает пакеты с полем IEEE 802.11 TA равным ehost. Поле TA отсутствует в кадрах управления, CTS (готовность к передаче) и ACK (подтверждение).

wlan addr1 ehost

Отбирает пакеты с первым адресом IEEE 802.11 равным ehost.

wlan addr2 ehost

Отбирает пакеты со вторым адресом IEEE 802.11 равным ehost. Второй адрес отсутствует в кадрах CTS (готовность к передаче) и ACK (подтверждение).

wlan addr3 ehost

Отбирает пакеты с третьим адресом IEEE 802.11 равным ehost. Третий адрес отсутствует в кадрах управления (control).

wlan addr4 ehost

Отбирает пакеты с четвертым адресом IEEE 802.11 равным ehost. Четвертый адрес присутствует только в кадрах WDS (Wireless Distribution System).

type wlan_type

Отбирает пакеты с типом кадра IEEE 802.11 wlan_type (mgt, ctl, data).

type wlan_type subtype wlan_subtype

Отбирает пакеты с типом кадра IEEE 802.11 wlan_type и субтипом wlan_subtype. Для типа mgt, субтип может принимать значения assoc-req, assoc-resp, reassoc-req, reassoc-resp, probe-req, probe-resp, beacon, atim, disassoc, auth, deauth, для типа ctl — ps-poll, rts, cts, ack, cf-end, cf-end-ack, а для data — data, data-cf-ack, data-cf-poll, data-cf-ack-poll, null, cf-ack, cf-poll, cf-ack-poll, qos-data, qos-data-cf-ack, qos-data-cf-poll, qos-data-cf-ack-poll, qos, qos-cf-poll и qos-cf-ack-poll.

subtype wlan_subtype

Отбирает пакеты с субтипом кадра IEEE 802.11 wlan_subtype, а кадр имеет тип, для которого указанный субтип определен.

dir <направление>

Отбирает кадры IEEE 802.11 указанного направления (nods, tods, fromds, dstods или число).

vlan [vlan_id]

Отбирает кадры IEEE 802.1Q VLAN. Если указан идентификатор VLAN, выбираются лишь пакеты, относящиеся в указанной виртуальной ЛВС. Первое ключевое слово vlan изменяет расчет смещения полей для оставшейся части выражения с учетом размера поля VLAN в заголовке кадра (4). Выражение vlan [vlan_id] может указываться несколько раз с учетом вложенности VLAN. Каждое такое выражение увеличивает смещение для полей на 4. Например,

vlan 100 && vlan 200

отберет кадры VLAN 200, инкапсулированные в кадры VLAN 100, а

vlan && vlan 300 && ip

отберет пакеты IPv4, инкапсулированные в кадры VLAN 300, инкапсулированные в любую виртуальную ЛВС.

mpls [label_num]

Отбирает пакеты MPLS. При наличии параметра [label_num] выбираются только пакеты с указанной меткой. Первое ключевое слово mpls меняет расчет смещения полей для оставшейся части выражения в предположении, что пакет относится к протоколу IP, инкапсулированному в MPLS. Выражение mpls [label_num] может указываться несколько раз с учетом вложенности меток. Каждое вхождение увеличивает смещение на 4.

Например, фильтр

mpls 100000 && mpls 1024

отберет пакеты с внешней меткой 100000 и внутренней меткой 1024, а

mpls && mpls 1024 && host 192.9.200.1

отберет пакеты с адресом 192.9.200.1, внутренней меткой 1024 и любой внешней меткой.

pppoed

Отбирает пакеты PPP-over-Ethernet Discovery (тип 0x8863)

pppoes [session_id]

Отбирает пакеты сессий PPP-over-Ethernet (тип 0x8864). При наличии параметра session_id будут отбираться лишь пакеты указанной сессии. Первое ключевое слово pppoes изменяет расчет смещения полей для оставшейся части выражения в предположении, что пакет относится к сессии PPPoE. Например, фильтр

pppoes 0x27 && ip

отберет пакеты IPv4, инкапсулированные в сессию PPPoE с идентификатором 0x27.

geneve [vni]

Отбирает пакеты Geneve (порт UDP 6081). При наличии параметра vni отбираются лишь соответствующие ему пакеты. Ключевое слово pppoes изменяет расчет смещения полей для оставшейся части выражения в предположении, что пакет относится к протоколу Geneve. Например, фильтр

geneve 0xb && ip

отберет пакеты IPv4, инкапсулированные с Geneve VNI 0xb (пакеты, напрямую инкапсулированные в Geneve, а также пакеты IP в кадрах Ethernet).

iso proto <протокол>

Собирает пакеты с указанным типом протокола OSI. Протокол может быть указан по номеру или имени (clnp, esis, isis).

clnp, esis, isis

Сокращение для iso proto p, где p — один из перечисленных протоколов.

l1, l2, iih, lsp, snp, csnp, psnp

Сокращение для типов IS-IS PDU.

vpi n

Собирает пакеты ATM с указанным идентификатором виртуального пути для SunATM (Solaris).

vci n

Собирает пакеты ATM с указанным идентификатором виртуального канала для SunATM (Solaris).

lane

Собирает пакеты эмуляции ЛВС (ATM LANE) для SunATM (Solaris). Первое ключевое слово lane в выражении изменяет проверки для остальной части фильтра в предположении, что пакет относится к пакетам эмуляции Ethernet или LANE LE Control. Если ключевое слово lane не указано, проверки выполняются в предположении LLC-инкапсуляции.

oamf4s

Собирает пакеты ATM для SunATM (Solaris), являющиеся сегментами потока ячеек OAM F4 (VPI=0, VCI=3).

oamf4e

Собирает пакеты ATM для SunATM (Solaris), относящиеся к сквозным потокам OAM F4 (VPI=0, VCI=4).

oamf4

Собирает пакеты ATM для SunATM (Solaris), являющиеся сегментами сквозного потока ячеек OAM F4 (VPI=0, (VCI=3 или VCI=4)).

oam

Собирает пакеты ATM для SunATM (Solaris), являющиеся сегментами сквозного потока ячеек OAM F4 (VPI=0, (VCI=3 или VCI=4)).

metac

Собирает пакеты ATM для SunATM (Solaris), относящиеся к сигнальным метаустройствам (VPI=0, VCI=1).

bcc

Собирает пакеты ATM для SunATM (Solaris), относящиеся к широковещательным сигнальным устройствам (VPI=0, VCI=2).

sc

Собирает пакеты ATM для SunATM (Solaris), относящиеся к сигнальным устройствам (VPI=0, VCI=5).

ilmic

Собирает пакеты ATM для SunATM (Solaris), относящиеся к клиентским устройствам ILMI (VPI=0, VCI=16).

connectmsg

Собирает пакеты ATM для SunATM (Solaris), относящиеся к сигнальным устройствам и содержащие сообщения Q.2931 Setup, Call Proceeding, Connect, Connect Ack, Release, Release Done.

metaconnect

Собирает пакеты ATM для SunATM (Solaris), относящиеся к сигнальным метаустройствам и содержащие сообщения Q.2931 Setup, Call Proceeding, Connect, Connect Ack, Release, Release Done.

expr <операция> expr

Возвращают логическое значение, соответствующее отношениям между левой и правой часть. В качестве операции могут использоваться >, <, >=, <=, =, !=, а операнды expr могут быть арифметическими выражениями, включающими целые константы (запись в стандарте C), бинарные операторы36 +, , *, /, %, &, |, ^, <<, >>, оператор размера (len) и данные из пакетов. Во всех операциях сравнения применяются целые числа без знака.

Для получения значений полей из пакетов применяется синтаксис:

proto [expr : size]

Параметр proto может содержать идентификатор одного из протоколов (ether, fddi, tr, wlan, ppp, slip, link, ip, arp, rarp, tcp, udp, icmp, ip6, radio) и задает уровень протокола37, для которого извлекаются данные. Отметим, что tcp, udp и другие протоколы верхних уровней относятся только к пакетам IPv4, а не IPv638. Параметр expr задает смещение в байтах относительно начала заголовка указанного уровня. Необязательный параметр size определяет размер интересующего поля в байтах и может принимать значения 1, 2 и 4 (по умолчанию 1 байт). Оператор размера, указываемый ключевым словом len, определяет размер пакета в байтах.

Например, выражению ether[0] & 1 != 0 будет соответствовать весь multicast-трафик, выражение ip[0] & 0xf != 5 позволяет собрать все пакеты IP, в которых присутствует поле опций, а фильтр ip[6:2] & 0x1fff = 0 соберет только нефрагментированные дейтаграммы IPv4 и первые фрагменты. При выборе полей из заголовков учитывается структура пакетов соответствующего уровня. Например, tcp[0] всегда будет возвращать первый байт заголовка TCP, игнорируя фрагменты.

Некоторые значения полей и смещений могут задаваться не только числами, но и именами. Поддерживаются значения icmptype39, icmp6type40, icmpcode, icmpcode, tcpflags41.

Примитивы в выражениях можно группировать с использованием

  • скобок42;

  • отрицания (! или not);

  • конкатенации (&& или and);

  • выбора варианта (|| или or).

Оператор отрицания имеет высший уровень приоритета, операции выбора и конкатенации имеют одинаковый приоритет и выполняются слева направо в порядке следования. Отметим, что для конкатенации недостаточно просто указать операнды рядом, а требуется явно задать операцию (&& или and).

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

not host vs and ace

является простым сокращением от

not host vs and host ace

Отметим, что эти выражения не эквивалентны фильтру not ( host vs or ace ).

Аргументы выражений могут передаваться программе tcpdump как один или множество аргументов (используйте более удобную для вас форму). В общем случае выражения, содержащие метасимволы командного интерпретатора, должны передаваться как один аргумент, заключенный в кавычки.

Примеры фильтров

Таблица 3. Примеры фильтров tcpdump.

Фильтр

Выполняемые действия

host sundown

Все пакеты, принимаемые и передаваемые хостом sundown

host helios and \( hot or ace \)

Пакеты, передаваемые между хостом helios и любым из хостов hot или ace.

ip host ace and not helios

Пакеты передаваемые между хостом ace и любым хостом, за исключением helios.

net ucb-ether

Все пакеты, передаваемые или принимаемые хостами сети ucb-ether.

'gateway snup and (port ftp or ftp-data)'

Весь трафик ftp, проходящий через шлюз snup43.

ip and not net localnet

Весь трафик, не относящийся к хостам локальной сети.

'tcp[tcpflags] & (tcp-syn|tcp-fin) != 0 and not src and dst net localnet'

Стартовые (SYN) и конечные (FIN) пакеты TCP, исключая соединения хостов локальной сети.

tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)

Пакеты IPv4 протокола HTTP через порт 80, исключая пакеты SYN, FIN и пакеты ACK без данных.

'gateway snup and ip[2:2] > 576'

Переданные через шлюз snup пакеты IP, размер которых превышает 576 байтов.

'ether[0] & 1 = 0 and ip[16] >= 224'

Широковещательные и групповые пакеты, которые не были переданы с использованием широковещательных и групповых адресов Ethernet.

'icmp[icmptype] != icmp-echo and icmp[icmptype] != icmp-echoreply'

Все пакеты ICMP, кроме запросов и откликов echo (т. е., кроме пакетов ping).

Формат вывода

Формат вывода tcpdump зависит от протокола. Ниже приведены краткие описания и примеры для большинства используемых форматов вывода.

Временные метки

По умолчанию в начале каждой строки вывода указывается временная метка в формате hh:mm:ss.frac, с поддерживаемым ядром разрешением. Метка указывает время ее добавления ядром и может включать задержку между завершением приема пакета интерфейсом и передачей ядру прерывания для чтения пакета, а также время обработки этого прерывания.

Заголовки канального уровня

При использовании опции -e выводится содержимое заголовков канального уровня. Для сетей Ethernet информация из заголовков включает адреса отправителя и получателя, протокол и размер кадра.

Для сетей FDDI опция -e обеспечивает вывод поля управления (frame control), адресов отправителя и получателя, а также размера кадра. Значение поля управления определяет интерпретацию остальной части кадра. Обычные кадры (например, содержащие дейтаграммы IP) являются “асинхронными” с уровнем приоритета от 0 до 7 (например async4). Предполагается, что такие кадры содержат пакеты 802.2 LLC. Заголовок LLC выводится в тех случаях, когда пакет не является дейтаграммой ISO или пакетом SNAP.

В сетях Token Ring опция -e обеспечивает вывод полей контроля доступа (access control) и управления кадром (frame control), адресов отправителя и получателя, а также размера кадра. Предполагается, что кадры содержат пакеты LLC. Независимо от наличия опции -e выводится информация о заданном отправителем маршруте (source routing), если пакет содержит такую информацию.

В сетях 802.11 опция -e выводит значения полей управления (frame control), все адреса из заголовка 802.11, а также размер кадра. Предполагается, что кадры содержат пакеты LLC.

Для каналов SLIP информация канального уровня включает индикатор направления (I для входящего трафика, O — для исходящего), тип пакета и сведения о компрессии44. Поле типа пакета выводится первым и может принимать значение ip, utcp или ctcp. Для пакетов IP дополнительной информации о канале не выводится. Для пакетов TCP вслед за типом выводится идентификатор соединения. Если для пакета используется компрессия, сжатый заголовок декодируется перед выводом. Для специальных случаев45 выводятся значения *S+n и *SA+n (где n — числовое значение), которые указывают величину изменения порядкового номера для пакета и подтверждения, соответственно. Для остальных пакетов могут выводиться индикаторы изменений — U (указатель важности), W (окно), A (подтверждение), S (порядковый номер) и I (идентификатор пакета), сопровождаемые величиной изменения (+n или -n) или указателем на новое значение параметра (=n). Далее выводится информация о размере данных в пакете и размер сжатого заголовка.

Например строка вывода

O ctcp * A+6 S+49 I+6 3 (6)

относится к исходящему сжатому пакету TCP с неявным идентификатором соединения. Порядковый номер подтверждения увеличился на 6, порядковый номер пакета — на 49, идентификатор пакета — на 6. Пакет содержит 3 байта данных и 6-байтовый сжатый заголовок.

Пакеты ARP и RARP

Информация, выводимая для пакетов arp и rarp, включает тип запроса и его аргументы. Выводимой информации вполне достаточно для понимания происходящих процессов. Ниже показан пример вывода для случая, когда хост rtsg открывает сессию rlogin с хостом csam:

arp who-has csam tell rtsg
arp reply csam is-at CSAM

Первая строка показывает запрос arp от хоста rtsg для получения адресов (MAC и IP) хоста csam. В ответ на это csam возвращает свои адреса (в примере IP-адрес обозначен как csam, а MAC-адрес — как CSAM). Если ввести команду с опцией -n, результат будет иметь вид

arp who-has 128.3.254.6 tell 128.3.254.68
arp reply 128.3.254.6 is-at 02:07:01:00:01:c4

Если же воспользоваться опцией -e, можно увидеть, что первый пакет является широковещательным (MAC-адрес отправителя показан как RSTG), поле типа содержит значение 0806 (ETHER_ARP), а размер пакета составляет 64 байта.

RTSG Broadcast 0806  64: arp who-has csam tell rtsg
CSAM RTSG 0806  64: arp reply csam is-at CSAM
Пакеты IPv4

Если заголовок канального уровня не выводится, для пакетов IPv4 после временной метки указывается заголовок IP. При наличии опции -v содержимое заголовка IPv4 указывается в скобках после заголовка IP или канального уровня. Базовый формат этой информации имеет вид

tos tos, ttl ttl, id id, offset offset, flags [flags], proto proto, length length, options (options)

Поле tos указывает тип обслуживания, отличные от нуля биты ECN указываются как ECT(1), ECT(0) или CE. Поле ttl указывает «время жизни» (нулевое значение опускается), id — поле идентификации IP, offset — смещение фрагмента, показывающее, является ли пакет частью фрагментированной дейтаграммы. Поле flags содержит флаги MF и DF — при установленном флаге MF выводится +, а при установленном флаге F — DFP. Если флаги не установлены, выводится точка (.). Поле proto содержит идентификатор протокола, length указывает общий размер пакета, а options — опции IP, если они имеются.

Далее для пакетов TCP и UDP указываются IP-адреса отправителя и получателя, а также номера портов TCP или UDP (номер пора отделяется от адреса точкой), а между отправителем и получателем размещается символ >. Для других протоколов выводятся адреса, разделенные символом >. При наличии данных вышележащего протокола, она выводится вслед за указанными полями.

Для фрагментированных дейтаграмм IP первый фрагмент содержит заголовок вышележащего протокола, а остальные фрагменты этот заголовок не включают. Данные фрагментации выводятся лишь при наличии опции -v.

Пакеты TCP

Формат вывода для протокола TCP (RFC 793) в общем случае имеет вид

src > dst: Flags [tcpflags], seq data-seqno, ack ackno, win window, urg urgent, options [opts], length len

Поля src и dst содержат IP-адреса и номера портов для отправителя и получателя. Поле Flags содержит комбинацию символов S (SYN), F (FIN), P (PUSH), R (RST), W (ECN CWR) и E (ECN-Echo) в соответствии с установленными для пакета флагами или один символ “.” (нет флагов). Поле data-seqno описывает занятую данным пакетом часть пространства порядковых номеров. Поле ack содержит порядковый номер, ожидаемый для следующей порции данных, передаваемой через это соединение в обратном направлении. Поле window показывает число байтов в приемном буфере, доступных для обратного направления в этом соединении. Поле urg показывает состояние флага важности (urgent) для данных из этого пакета. Поле options содержит опции TCP, заключенные в угловые скобки.

Поля src, dst и flags присутствуют во всех случаях, вывод остальных полей зависит от данных в заголовке TCP.

Ниже показан набор пакетов, передаваемых при организации хостом rtsg сессии rlogin с хостом csam.

rtsg.1023 > csam.login: S 768512:768512(0) win 4096 <mss 1024>
csam.login > rtsg.1023: S 947648:947648(0) ack 768513 win 4096 <mss 1024>
rtsg.1023 > csam.login: . ack 1 win 4096
rtsg.1023 > csam.login: P 1:2(1) ack 1 win 4096
csam.login > rtsg.1023: . ack 2 win 4096
rtsg.1023 > csam.login: P 2:21(19) ack 1 win 4096
csam.login > rtsg.1023: P 1:2(1) ack 21 win 4077
csam.login > rtsg.1023: P 2:3(1) ack 21 win 4077 urg 1
csam.login > rtsg.1023: P 3:4(1) ack 21 win 4077 urg 1

Первая строка показывает, что порт TCP с номером 1023 хоста rtsg отправил пакет в порт login хоста csam. Символ S говорит о наличии в пакете флага SYN. Порядковый номер пакета равен 768512 и данных в пакете не содержится46. Пакет не содержит в себе подтверждения, доступный размер приемного окна составляет 4096 байтов, а запрошенное значение MSS составляет 1024 байта.

Сайт csam отправляет в ответ подобный полученному пакет, включающий подтверждение для полученного от rtsg пакета SYN. После этого rtsg подтверждает хосту csam получение от него пакета SYN. Точка (.) в поле флагов говорит о том, что пакет не содержит ни одного флага. Данных в пакете не содержится, поэтому в строке вывода отсутствуют значения порядковых номеров. Отметим, что для подтверждения в строке 3 указан порядковый номер 1. Когда tcpdump видит первый пакет в данном соединении, выводится порядковый номер из этого пакета. Для последующих пакетов данного соединения выводятся значения разницы между порядковым номером для текущего пакета и начальным порядковым номером. Это значит, что для всех пакетов, кроме первого, порядковые номера указываются относительно начала потока данных для соединения и первый байт данных имеет номер 1. Опция -S (стр. 4) отключает относительную нумерацию и обеспечивает вывод порядковых номеров в соответствии со значениями в пакетах.

В строке 6 показан пакет, который rtsg отправляет хосту csam с 19 байтами данных (байты со 2 по 20). Пакет передается с флагом PUSH. Строка 7 содержит отправленное хостом csam подтверждение приема данных от хоста rtsg вплоть до байта с номером 21 (не включая этот байт). Большая часть этих данных сохраняется в приемном буфере, поскольку csam показывает уменьшение приемного окна на 19 байтов. В этом пакете csam также передает хосту rtsg 1 байт данных. В строках 8 и 9 показана передача хостом csam двух важных (urg) байтов данных, отправленных с использованием флага выталкивания PUSH.

Если используется достаточно малый кадр захвата (см. описание опции -s на стр. 4), tcpdump может не получить заголовок TCP полностью. В таких случаях интерпретируется полученная часть заголовка, а в строке вывода помещается маркер [|tcp], показывающий невозможность полной интерпретации. Если заголовок содержит некорректную опцию47, строка вывода будет содержать маркер [bad opt] и последующие опции не будут интерпретироваться, поскольку невозможно корректно определить начало следующей опции. Если поле размера заголовка указывает на присутствие опций, но размер пакета IP недостаточно велик для включения всех опций в пакет, tcpdump будет помещать в строке вывода маркер [bad hdr length].

Сбор пакетов TCP с заданными комбинациями флагов (SYN-ACK, URG-ACK и т. п.)

Поле флагов заголовка TCP содержит 8 элементов — CWR | ECE | URG | ACK | PSH | RST | SYN | FIN.

Предположим, что нужно собрать пакеты, используемые для организации нового соединения TCP. Напомним, что протокол TCP использует 3-этапную процедуру организации новых соединений, как показано ниже.

  1. Инициатор соединения передает пакет с установленным флагом SYN.

  2. Получатель этого пакета передает отклик с флагами SYN и ACK.

  3. Инициатор передает в ответ пакет с флагом ACK.

Создадим фильтр, который будет собирать пакеты, содержащие только флаг SYN (этап 1). Пакеты этапа 2 (SYN-ACK) не будут включаться, поскольку они являются просто откликами на стартовый запрос SYN. Прежде, чем строить выражение для фильтра, вспомним структуру заголовка TCP без опций.

Таблица 4. Структура заголовка TCP.

0 15

31

Порт отправителя

Порт получателя

Порядковый номер

Номер подтверждения

HL

резерв

C

E

U

A

P

R

S

F

Размер окна

Контрольная сумма TCP

Указатель важности

Заголовок TCP состоит из 20 октетов, если не используются необязательные поля опций. Первая строка таблицы 4 соответствует октетам 0 — 3, вторая — октетам 4 — 7 и т. д. Поле битов управления (флагов) TCP содержится в октете 13. Пронумеруем биты флагов справа налево (в соответствии с ростом значимости битов).

Таблица. 5 Биты флагов TCP.

7

6

5

4

3

2

1

0

27=128

26=64

25=32

24=16

23=8

22=4

21=2

20=1

CWR

ECE

URG

ACK

PSH

RST

SYN

FIN

Таким образом, значение октета флагов при наличии в нем только флага SYN будет составлять

0*128 + 0*64 + 0*32 + 0*16 + 0*8 + 0*4 + 1*2 + 0*1 = 2

и для выделения пакетов с флагом SYN можно воспользоваться выражением

tcp[13] == 2

Указав интересующий интерфейс, мы можем собрать пакеты с помощью команды

tcpdump -i <интерфейс> tcp[13] == 2

Эту команду можно перевести на человеческий язык словами: «Собрать с указанного интерфейса пакеты TCP, имеющие в тринадцатом октете заголовка значение 2».

Далее предположим, что нужно собрать пакеты с флагом SYN, независимо от состояния флага ACK и иных флагов. Посмотрим, какое значение будет иметь октет флагов для пакетов SYN-ACK:

|C|E|U|A|P|R|S|F|
|0 0 0 1 0 0 1 0|

В десятичном формате значение 00010010 будет равно 18

0*128 + 0*64 + 0*32 + 1*16 + 0*8 + 0*4 + 1*2 + 0*1 = 18

Однако, мы не можем использовать выражение

tcp[13] == 18

поскольку ему будут соответствовать только пакеты с установленными флагами SYN и ACK, но не будут соответствовать пакеты, имеющие только флаг SYN, который интересует нас в первую очередь.

Для сбора пакетов SYN, независимо от значения флага ACK, следует использовать маску 00000010 (десятичное значение 2). Таким образом, мы можем ввести выражение:

tcpdump -i <интерфейс> 'tcp[13] & 2 == 2'

которое позволит нам собирать пакеты с установленным флагом SYN независимо от присутствия других флагов. Выражение нужно поместить в кавычки или использовать символ \ для экранирования специального символа &.

Пакеты UDP

Формат вывода пакетов UDP можно проиллюстрировать на примере пакета rwho

actinide.who > broadcast.who: udp 84

Приведенная строка говорит о том, что порт who хоста actinide передал дейтаграмму UDP в порт who с использованием широковещательного адреса IP. Пакет содержит 84 байта пользовательских данных.

Для некоторых служб, работающих по протоколу UDP, распознаются протоколы вышележащего уровня (по номеру порта) и для таких протоколов выводится соответствующая информация. В частности, tcpdump выводит дополнительные сведения для пакетов DNS48 и вызовов NFS с помощью Sun RPC49.

Запросы UDP к серверам DNS

Формат вывода для запросов DNS имеет вид

src > dst: id op? flags qtype qclass name (len)

Например

h2opolo.1538 > helios.domain: 3+ A? ucbvax.berkeley.edu. (37)

говорит, что хост h2opolo запрашивает у сервера имен helios адресную запись (qtype=A) для имени ucbvax.berkeley.edu. Идентификатор запроса имеет значение 3. Знак + показывает наличие флага recursion desired50. Размер пакета составляет 37 байтов без учета заголовков UDP и IP. Поскольку пакет содержит обычный запрос, поле op опущено. Если бы это поле содержало иную операцию, соответствующий код был бы выведен между 3 и +. Поле qclass также содержит стандартное значение C_IN, которое опущено при выводе. Любое другое значение qclass было бы выведено вслед за символом A.

При анализе пакета проверяется наличие в нем аномалий и в результате такой проверки строка вывода может содержать дополнительные поля, заключенные в квадратные скобки. Если запрос содержит разделы answer (ответ), authority records (запись о полномочиях) или additional records (дополнительные записи), значения ancount, nscount или arcount выводятся как [na], [nn] или [nau], где n показывает значение соответствующего счетчика. Если установлены какие-либо биты отклика (AA, RA или rcode) или в байтах 2 и 3 установлены любые биты MBZ (должно быть нулем), выводится поле [b2&3=x], где x — шестнадцатеричное значение байтов 2 и 3 из заголовка.

UDP-отклики от серверов DNS

Для вывода откликов сервера имен используется формат

src > dst:  id op rcode flags a/n/au type class data (len)

Например,

helios.domain > h2opolo.1538: 3 3/3/7 A 128.32.137.3 (273)
helios.domain > h2opolo.1537: 2 NXDomain* 0/1/0 (97)

Первая строка показывает, что сервер helios отвечает на запрос с id=3 от хоста h2opolo сообщениям с тремя записями answer, 3 записями NS и 7 дополнительными записями. Первая запись answer имеет тип A (адрес) и содержит IP-адрес указанного в запросе хоста (128.32.137.3). Общий размер отклика составляет 273 байта без учета заголовков UDP и IP. Поля op (Query) и код отклика (NoError) были опущены при выводе.

Во второй строке helios отвечает на запрос 2 с кодом NXDomain (несуществующий домен) без записей answer, с одной записью NS и без записей authority. Символ * показывает, установленный бит полномочного отклика (authoritative answer). Ввиду отсутствия записей answer не выводится никакой информации о типе, классе и данных.

В строке вывода могут также появляться индикаторы флагов RA (рекурсия доступна) “ и TC (усеченное сообщение) “|”. Если раздел question (вопрос) не содержит в точности одну запись, выводится поле [nq].

Отметим, что запросы и отклики DNS могут быть достаточно велики и принятое по умолчанию значение кадра захвата (68 байтов) может не обеспечить достаточное количество данных из пакета. Для просмотра трафика DNS целесообразно увеличить размер кадра захвата вдвое с помощью опции -s 128.

Декодирование SMB/CIFS

Программа tcpdump поддерживает функции декодирования пакетов SMB/CIFS/NBT, использующих порты UDP/137, UDP/138 и TCP/139. Поддерживаются также некоторые примитивы декодирования данных IPX и NetBEUI SMB.

По умолчанию декодирование происходит с минимальным выводом информации, а для увеличения информативности служит опция -v. Отметим, что при использовании опции -v один пакет SMB может занимать больше экранной страницы, поэтому указывайте опцию только при необходимости, чтобы не утонуть в море выводимых на экран данных.

При декодировании сеансов SMB, содержащих текстовые строки Unicode может потребоваться установка переменной окружения USE_UNICODE =1.

Информацию о формате пакетов SMB вы сможете найти на сайте www.cifs.org или одном из зеркал samba.org.

Запросы и отклики NFS

Запросы и отклики Sun NFS51 имеют вид:

src.sport > dst.nfs: NFS request xid xid len op args 
src.nfs > dst.dport: NFS reply xid xid reply stat len op results

Ниже показан пример вывода информации для пакетов NFS

sushi.6709 > wrl.nfs: 
   112 readlink fh 21,24/10.73165
wrl.nfs > sushi.6709: 
   reply ok 40 readlink "../var"
sushi.201b > wrl.nfs: 
   144 lookup fh 9,74/4096.6878 "xcolors"
wrl.nfs > sushi.201b: 
   reply ok 128 lookup fh 9,74/4134.3150

Первая строка показывает, что хост sushi передает транзакцию с идентификатором 670952 хосту wrl. Размер запроса составляет 112 байтов без учета заголовков UDP и IP. Запрашиваемая операция readlink53 для файла с идентификатором (handle) fh 21,24/10.731657119 была успешно выполнена и хост wrl возвращает результат ok с содержимым символьной ссылки.

Затем sushi запрашивает у хоста wrl поиск файла xcolors в каталоге 9,74/4096.6878 и wrl возвращает отклик с идентификатором транзакции.

При использовании опции -v вывод становится более информативным54

sushi.1372a > wrl.nfs: 148 read fh 21,11/12.195 8192 bytes @ 24576
wrl.nfs > sushi.1372a: reply ok 1472 read REG 100664 ids 417/0 sz 29388

В первой строке показан запрос sushi к хосту wrl на чтение 8192 байтов из файла 21,11/12.195, начиная со смещения 24576. Хост wrl возвращает результат ok, показанный во второй строке пакет является первым фрагментом отклика, содержащим 1472 байта прочитанных данных. Последующие фрагменты не имеют заголовков NFS и UDP, поэтому информация об этих пакетов может не появиться на экране, если вы задали в команде тот или иной фильтр. Благодаря использованию опции -v выводятся также некоторые атрибуты прочитанного файла (REG — обычный файл, восьмеричное представление прав доступа, идентификаторы владельца и группы, а также размер файла).

При использовании опции -vv объем выводимой информации может дополнительно возрасти.

Отметим, что запросы NFS могут быть достаточно большими и при использовании опции -v выводимая информация может занять несколько экранных страниц. В некоторых случаях будет полезно уменьшить размер кадра захвата с помощью опции -s (например, -s 192).

Отклики NFS не указывают явно операции RPC, вместо этого tcpdump сохраняет информацию о последних запросах и при выводе откликов указывает соответствующие идентификаторы транзакций.

Запросы и отклики AFS

Вывод информации для запросов и откликов AFS55 имеет вид

src.sport > dst.dport: rx packet-type
src.sport > dst.dport: rx packet-type service call call-name args
src.sport > dst.dport: rx packet-type service reply call-name args

Ниже показан пример вывода информации для пакетов AFS

elvis.7001 > pike.afsfs:
     rx data fs call rename old fid 536876964/1/1 ".newsrc.new"
     new fid 536876964/1/1 ".newsrc"
pike.afsfs > elvis.7001: rx data fs reply rename

В первой строке хост elvis передает пакет RX хосту pike. Этот пакет адресован файловому серверу (fs) и начинает вызов удаленной процедуры (RPC). Вызов RPC содержит команду rename (переименовать) с идентификатором старого каталога 536876964/1/1 и именем .newsrc.new, а также новым идентификатором 536876964/1/1 и именем .newsrc. Хост pike возвращает отклик RPC с информацией об изменении имени файла.

В общем случаем все пакеты AFS RPC декодируются по меньшей мере как имена процедур RPC. Во многих случаях декодируется также один или несколько передаваемых процедуре аргументов.

Формат вывода должен быть понятен для тех, кто знаком с AFS и RX.

При использовании опции -v обеспечивается вывод дополнительной информации (идентификаторы вызовов RX, номера вызовов, порядковые номера, флаги пакетов RX). Опция -vv дополнительно увеличивает объем выводимой информации (в частности, сведений о согласовании MTU для пакетов RX ack), а опция -vvv обеспечивает также вывод параметров безопасности и идентификаторов сервиса.

Для пакетов abort выводятся коды ошибок (за исключением пакетов Ubik, поскольку эти пакеты используются для обозначения пакетов yes vote протокола Ubik).

Отметим, что запросы AFS могут быть достаточно велики, поэтому использование флага -v иной раз будет приводить к выводу для пакета многостраничной информации. Можно задать размер кадра захвата с помощью опции -s для обеспечения более читаемых результатов (например, -s 256).

Отклики AFS явно не указывают операции RPC, поэтому tcpdump отслеживает последние запросы и помечает отклики идентификаторами соответствующих запросов.

KIP AppleTalk (DDP по протоколу UDP)

Пакеты AppleTalk DDP, инкапсулированные в дейтаграммы UDP, извлекаются из дейтаграмм и отображаются как пакеты DDP (заголовки UDP отбрасываются). Для преобразования имен сетей и хостов AppleTalk служит файл /etc/atalk.names, строки которого имеют форму адрес (номер) — имя

1.254     ether
16.1      icsd-net
1.254.110 ace

В приведенном примере первые две строки содержат имена сетей AppleTalk, а третья — имя хоста56. Для разделения номера и имени в файле могут служить пробелы или символы табуляции. Файл /etc/atalk.names может содержать пустые строки и строки комментариев, начинающиеся с символа #.

Адреса AppleTalk выводятся в формате net.host.port, например,

144.1.209.2 > icsd-net.112.220
office.2 > icsd-net.112.220
jssmag.149.235 > icsd-net.2

Если файл /etc/atalk.names не содержит записи для той или иной сети или хоста, соответствующее поле выводится в цифровом формате. В первой строке показан пакет NBP (DDP порт 2), отправленный узлом 209 сети 144.1 в порт 220 узла 112 сети icsd-net. Вторая строка отличается от первой только тем, что указано также символьное имя отправителя (office). В третьей строке показан пакет, отправленный из порта 235 хостом 149 сети jssmag всем хостам57 сети icsd-net, прослушивающим порт NBP

Пакеты протоколов NBP (name binding protocol) и ATP (AppleTalk transaction protocol) выводятся с интерпретацией их содержимого. Для остальных протоколов просто выводится дамп имени протокола или его номера, если имя неизвестно, и размер пакета.

Пакеты NBP выводятся в формате, подобном приведенному ниже:

icsd-net.112.220 > jssmag.2: nbp-lkup 190: "=:LaserWriter@*"
jssmag.209.2 > icsd-net.112.220: nbp-reply 190: "RM1140:LaserWriter@*" 250
techpit.2 > icsd-net.112.220: nbp-reply 190: "techpit:LaserWriter@*" 186

Первая строка показывает запрос на преобразование имени для принтеров LaserWriter, переданный хостом 112 сети icsd по широковещательному адресу сети jssmag. Идентификатор запроса nbp имеет значение 190. Вторая строка содержит отклик на этот запрос от хоста jssmag.209, сообщающего о наличии ресурса LaserWriter с именем RM1140, зарегистрированного на порту 250. В третьей строке показан другой отклик на тот же запрос, говорящий, что хост techpit имеет ресурс LaserWriter с именем techpit, зарегистрированный на порту 186.

Пример формата вывода пакетов ATP показан ниже:

jssmag.209.165 > helios.132: atp-req  12266<0-7> 0xae030001
helios.132 > jssmag.209.165: atp-resp 12266:0 (512) 0xae040000
helios.132 > jssmag.209.165: atp-resp 12266:1 (512) 0xae040000
helios.132 > jssmag.209.165: atp-resp 12266:2 (512) 0xae040000
helios.132 > jssmag.209.165: atp-resp 12266:3 (512) 0xae040000
helios.132 > jssmag.209.165: atp-resp 12266:4 (512) 0xae040000
helios.132 > jssmag.209.165: atp-resp 12266:5 (512) 0xae040000
helios.132 > jssmag.209.165: atp-resp 12266:6 (512) 0xae040000
helios.132 > jssmag.209.165: atp-resp*12266:7 (512) 0xae040000
jssmag.209.165 > helios.132: atp-req  12266<3,5> 0xae030001
helios.132 > jssmag.209.165: atp-resp 12266:3 (512) 0xae040000
helios.132 > jssmag.209.165: atp-resp 12266:5 (512) 0xae040000
jssmag.209.165 > helios.132: atp-rel  12266<0-7> 0xae030001
jssmag.209.133 > helios.132: atp-req* 12267<0-7> 0xae030002

Хост jssmag.209 инициирует транзакцию 12266 с хостом helios, запрашивая до 8 пакетов (<0-7>). Шестнадцатеричное число в конце строки содержит значение поля userdata из запроса.

Хост helios отвечает на полученный запрос 8 пакетами по 512 байтов. Число после номера транзакции указывает порядковый номер пакета для данной транзакции, а число в скобках — размер данных в пакете без учета заголовка ATP. Символ * для пакета 7 показывает наличие флага EOM.

Хост jssmag.209 после получения пакетов запрашивает повторную передачу пакетов 3 и 5, а helios повторяет эти пакеты, после чего jssmag.209 завершает транзакцию. В последней строке показан новый запрос хоста jssmag.209. Символ * показывает, что флаг XO (exactly once) для пакета не установлен.

Перевод на русский язык

Николай Малых

nmalykh@protokols.ru

1Promiscuous — “Неразборчивый” режим, при котором драйвер устройства захватывает все передаваемые через среду пакеты. В нормальном режиме драйвер обычно читает из среды лишь пакеты, адресованные данному устройству.

2Поддержка “битов возможностей” (capability bit) обеспечивается в ядре Linux начиная с версии 2.2.

3Например, Windows или UNIX-системы, в которых не поддерживается команда ifconfig -a

4Например, его можно увидеть с помощью команды ps.

5Интерфейс может быть переведен в неразборчивый режим другими программами, поэтому использование флага -p отнюдь не гарантирует работу интерфейса в обычном режиме — программа просто не будет переводить этот интерфейс в неразборчивый режим. Кроме того, даже в обычном режиме захватываться будут не только пакеты, адресованные этому интерфейсу, поскольку в сети всегда присутствуют широковещательные пакеты и могут использоваться пакеты с групповыми адресами (multicast).

6В SunOS NIT минимум составляет 96 байтов.

7Например, при захвате пакетов в сети Ethernet с помощью команда tcpdump -s 12 на выходе будут появляться строки вида 22:31:43.385357 [|ether], показывающие, что отсечка пакетов произошла на уровне Ethernet.

8Протокол Ad-hoc On-demand Distance Vector.

9Common Address Redundancy Protocol — базовый протокол для избыточных (резервных) адресов.

10Протокол Cisco NetFlow.

11Link Management Protocol — протокол управления каналом.

12Pragmatic General Multicast.

13ZMTP/1.0 внутри PGM/EPGM.

14REdis Serialization Protocol.

15Протокол Remote Procedure Call (удаленный вызов процедур).

16Протокол Real-Time Applications (приложения в реальном масштабе времени).

17Протокол управления приложениями реального времени (Real-Time Applications control protocol).

18Простой протокол сетевого управления (Simple Network Management Protocol).

19Тривиальный протокол обмена файлами (Trivial File Transfer Protocol).

20Visual Audio Tool.

21Распределенные доски White Board.

22ZeroMQ Message Transport Protocol 1.0.

23Virtual eXtensible Local Area Network.

24fddi в действительности является псевдонимом ether и при анализе примитива оба классификатора трактуются как “канальный уровень, используемый указанным интерфейсом”. Заголовки FDDI содержат адреса отправителя и получателя, подобные адресам Ethernet, поля типа также зачастую содержат значения, подобные используемым для Ethernet, поэтому можно фильтровать эти поля в кадрах FDDI как и аналогичные поля кадров Ethernet. Заголовки FDDI содержат и другие поля, но их нельзя указать в фильтрах.

25tr является псевдонимом ether, поскольку оба типа кадров используют весьма похожую структуру заголовков.

26Идентификатор протокола wlan (беспроводные сети 802.11) является псевдонимом ether. В заголовках 802.11 адрес получателя содержится в поле DA, отправителя — в поле SA, а поля BSSID, RA и TA не проверяются фильтрами.

27Например, примитиву src foo будут соответствовать все пакеты ip, arp и rarp, исходящие от хоста foo.

28MAC-адрес записывается в формате xx:xx:xx:xx:xx:xx

29Т. е., адрес отправителя или получателя на канальном уровне (например, ethernet) соответствует адресу хоста, заданному значением <шлюз>, но IP-адреса отправителя и получателя в заголовке пакета не совпадают с IP-адресом указанного шлюза.

30Интерфейс не имеет маски или сбор пакетов осуществляется со всех интерфейсов хоста Linux (интерфейс any).

31Перечисленные здесь имена протоколов могут использоваться также в качестве ключевых слов, поэтому имени протокола должен предшествовать символ \ (например, \arp).

32Destination Service Access Point — точка доступа к сервису для получателя.

33Source Service Access Point — точка доступа к сервису для отправителя.

34Поддержка имен DECNET обеспечивается только на хостах ULTRIX, настроенных для использования DECNET.

35Это правило применимо только к пакетам, собранным в файл с помощью программы pf (OpenBSD).

36Операторы % и ^ поддерживаются фильтрами в ядре Linux, начиная с версии 3.7, а в остальных случаях эти операторы используют фильтры в пользовательском пространстве, что существенно повышает издержки при отборе и может вести к потере пакетов.

37Протоколы ether, fddi, wlan, tr, ppp, slip и link указывают на канальный уровень, radio указывает «радио-заголовок», добавляемый к некоторым выборкам 802.11.

38Поддержка IPv6 будет реализована в следующих версиях.

39Поле типа ICMP, которое может принимать значения icmp-echoreply, icmp-unreach, icmp-sourcequench, icmp-redirect, icmp-echo, icmp-routeradvert, icmp-routersolicit, icmp-timxceed, icmp-paramprob, icmp-tstamp, icmp-tstampreply, icmp-ireq, icmp-ireqreply, icmp-maskreq, icmp-maskreply.

40Поле типа ICMPv6, которое может принимать значения icmp6-echo, icmp6-echoreply, icmp6-multicastlistenerquery, icmp6-multicastlistenerreportv1, icmp6-multicastlistenerdone, icmp6-routersolicit, icmp6-routeradvert, icmp6-neighborsolicit, icmp6-neighboradvert, icmp6-redirect, icmp6-routerrenum, icmp6-nodeinformationquery, icmp6-nodeinformationresponse, icmp6-ineighbordiscoverysolicit, icmp6-ineighbordiscoveryadvert, icmp6-multicastlistenerreportv2, icmp6-homeagentdiscoveryrequest, icmp6-homeagentdiscoveryreply, icmp6-mobileprefixsolicit, icmp6-mobileprefixadvert, icmp6-certpathsolicit, icmp6-certpathadvert, icmp6-multicastrouteradvert, icmp6-multicastroutersolicit, icmp6-multicastrouterterm

41Для флагов TCP можно указать идентификаторы tcp-fin, tcp-syn, tcp-rst, tcp-push, tcp-ack, tcp-urg, tcp-ece, tcp-cwr.

42В зависимости от используемого командного интерпретатора перед символами открывающих и закрывающих скобок может потребоваться включение символа экранирования.

43Кавычки позволяют избавиться от ошибок при анализе скобок командным интерпретатором.

44Компрессия заголовков TCP/IP для каналов SLIP описана в RFC 1144.

45RFC 1144 определяет как специальные случаи интерактивный трафик и передачу больших объемов трафика.

46Об этом говорит запись first:last(nbytes), в которой указывается порядковый номер первого байта в этом и следующем за ним (т. е. номер последнего байта в данном пакете + 1) пакетах и число байтов, содержащихся в пакете.

47Размер опции слишком мал или выходит за пределы указанного размера заголовка.

48Спецификация протокола DNS (Domain Name System) приведена в RFC 1034 и RFC 1035.

49Спецификация протокола RPC (Remote Procedure Call — удаленный вызов процедур) содержится в RFC 1050.

50При отсутствии записи на сервере имен следует сделать рекурсивный запрос к другому серверу.

51Network File System — сетевая файловая система.

52Номер, указанный после имени отправителя, задает не порт, а номер транзакции.

53Прочесть символьную ссылку.

54При использовании опции -v будут выводиться также поля заголовков IP (TTL, ID, length, fragmentation), которые опущены в приведенном примере.

55Andrew File System.

56Хост отличается от сети наличием в номере третьего октета.

57Отметим, что широковещательный адрес 255 задается просто именем или номером сети без указания хоста. По этой причине разумно сохранять имена хостов и сетей в файле /etc/atalk.names отдельно.

Рубрика: Linux, Измерения и тестирование | Комментарии к записи Пакет tcpdump отключены

RFC 8639 Subscription to YANG Notifications

Internet Engineering Task Force (IETF)                           E. Voit
Request for Comments: 8639                                 Cisco Systems
Category: Standards Track                                       A. Clemm
ISSN: 2070-1721                                                Futurewei
                                                      A. Gonzalez Prieto
                                                               Microsoft
                                                       E. Nilsen-Nygaard
                                                             A. Tripathy
                                                           Cisco Systems
                                                          September 2019

Subscription to YANG Notifications

Подписка на уведомления YANG

PDF

Аннотация

Этот документ определяет модель данных YANG и связанные механизмы для подписки получателей на поток событий от издателя. Применение этих методов позволяет подписчику запрашивать и получать продолжающийся настраиваемый поток создаваемой издателем информации.

Статус документа

Документ относится к категории Internet Standards Track.

Документ является результатом работы IETF1 и представляет согласованный взгляд сообщества IETF. Документ прошёл открытое обсуждение и был одобрен для публикации IESG2. Дополнительную информацию о стандартах Internet можно найти в разделе 2 RFC 7841.

Информацию о текущем статусе документа, ошибках и способах обратной связи можно найти по ссылке https://www.rfc-editor.org/info/rfc8639.

Авторские права

Авторские права (Copyright (c) 2019) принадлежат IETF Trust и лицам, указанным в качестве авторов документа. Все права защищены.

К документу применимы права и ограничения, указанные в BCP 78 и IETF Trust Legal Provisions и относящиеся к документам IETF (http://trustee.ietf.org/license-info), на момент публикации данного документа. Прочтите упомянутые документы внимательно. Фрагменты программного кода, включённые в этот документ, распространяются в соответствии с упрощённой лицензией BSD, как указано в параграфе 4.e документа IETF Trust Legal Provisions, без каких-либо гарантий (как указано в Simplified BSD License).

Документ может содержать материалы из IETF Document или IETF Contribution, опубликованных или публично доступных до 10 ноября 2008 года. Лица, контролирующие авторские права на некоторые из таких документов, могли не предоставить IETF Trust права разрешать внесение изменений в такие документы за рамками процессов IETF Standards. Без получения соответствующего разрешения от лиц, контролирующих авторские права этот документ не может быть изменён вне рамок процесса IETF Standards, не могут также создаваться производные документы за рамками процесса IETF Standards за исключением форматирования документа для публикации или перевода с английского языка на другие языки.

1. Введение

Этот документ задаёт модель данных YANG и связанные с ней механизмы подписки на уведомления о потоках событий у издателя. Это фактически обеспечивает возможность публикации по подписке, когда настраиваемые потребности в сведениях и права доступа для каждого целевого получателя воспринимаются издателем до того, как соответствующие записи будут размещены и вытолкнуты (push). Подписчик получает продолжающийся настроенный поток публикуемых издателем сведений.

Описанная здесь функциональность не зависит от транспорта, а для настройки или динамического оповещения о подписках может служить такой транспорт, как протокол настройки сети (Network Configuration Protocol или NETCONF) [RFC6241] или RESTCONF [RFC8040]. Привязки для доставки записей о событиях по протоколу NETCONF и RESTCONF описаны в [RFC8640] и [RESTCONF-Notif], соответственно.

Модель данных YANG, заданная здесь, соответствует архитектуре хранилищ данных управления сетью (Network Management Datastore Architecture или NMDA), определённой в [RFC8342].

1.1. Мотивация

Ограничения для подписки, указанные в [RFC5277], были частично смягчены в [RFC7923]. Мотивом этой работы является разрешение оставшихся вопросов. Основные возможности, поддерживаемые этим документом, включают:

  • несколько подписок в одной транспортной сессии;

  • поддержка динамической и настраиваемой подписки;

  • изменение имеющейся подписки;

  • рабочие счётчики на уровне подписки;

  • согласование параметров подписки (на основе советов, возвращаемых как часть отклонённого запроса);

  • уведомления о смене состояния подписки (например, приостановка издателем, изменение параметров);

  • независимость от транспорта.

1.2. Терминология

Ключевые слова необходимо (MUST), недопустимо (MUST NOT), требуется (REQUIRED), нужно (SHALL), не следует (SHALL NOT), следует (SHOULD), не нужно (SHOULD NOT), рекомендуется (RECOMMENDED), не рекомендуется (NOT RECOMMENDED), возможно (MAY), необязательно (OPTIONAL) в данном документе интерпретируются в соответствии с BCP 14 [RFC2119] [RFC8174] тогда и только тогда, когда они выделены шрифтом, как показано здесь.

Client — клиент

Определён в [RFC8342].

Configuration — конфигурация

Определён в [RFC8342].

Configuration datastore — хранилище конфигурации

Определён в [RFC8342].

Configured subscription — настраиваемая подписка

Подписка, организованная путём настройки в хранилище конфигурации.

Dynamic subscription — динамическая подписка

Подписка, динамически задаваемая подписчиком вызовом удалённой процедуры (Remote Procedure Call или RPC).

Event — событие

Что-то, представляющее интерес, например, смена конфигурации, отказ, смена статуса, достижение порога, внешнее событие в системе.

Event occurrence time — время события

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

Event record — запись о событии

Набор сведений о событии.

Event stream — поток событий

Продолжающийся, хронологически упорядоченный набор событий, собранных в том или ином контексте.

Event stream filter — фильтр потока событий

Критерий оценки, применяемый к записям потока событий. Записи проходят фильтр при соответствии критериям.

Notification message — уведомляющее сообщение (уведомление)

Сведения для получателя, указывающие, что произошло одно или несколько событий.

Publisher — издатель

Сущность, отвечающая за поток уведомляющих сообщений в соответствии с подпиской.

Receiver — получатель

Целью (элемент), которой издатель выталкивает записи о событиях в соответствии с подпиской. Для динамической подписки получатель и подписчик совпадают.

Subscriber — подписчик

Клиент, способный запросить и согласовать условия генерации и выталкивания издателем записей о событиях. Для динамической подписки получатель и подписчик совпадают.

Subscription — подписка

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

Используемые в документе диаграммы деревьев YANG соответствуют нотации [RFC8340].

1.3. Обзор решения

Этот документ описывает независимый от транспорта механизм для подписки и получения содержимого потока событий у издателя. Механизм работает на основе подписки. Поддерживается два типа подписки, указанных ниже.

  1. Динамическая подписка, когда подписчик инициирует организацию подписки от издателя через RPC. Если издатель способен обслужить запрос, он воспринимает его и начинает выталкивать уведомления для подписчика. При неспособности издателя обслужить запрос он возвращает сообщение об ошибке, которое может включать советы по параметрам подписки, которые позволят воспринять новый запрос.

  2. Настраиваемые подписки, которыми можно управлять с помощью конфигурации, чтобы издатель мог передавать получателю уведомления. Поддержка настраиваемой подписки необязательна, а её доступность анонсируется через YANG feature.

Ниже указаны дополнительные характеристики, по которым различается динамическая и настраиваемая подписка.

  • Срок действия динамической подписки привязан к создавшей её транспортной сессии. Для ориентированного на соединения транспорта с поддержкой состояния, такого как NETCONF, потеря транспортной сессии ведёт к немедленному прекращению всех связанных с ней динамических подписок. Для транспорта без организации соединений или поддержки состояния, такого как HTTP, отсутствие подтверждений приёма последовательного набора уведомлений и/или сообщений keep-alive может вызывать прерывание динамической подписки. Это отличается от настраиваемой подписки, срок действия котрой определяет соответствующая конфигурация, присутствующая у издателя. Привязка к конфигурации означает, что (1) настроенные подписчики могут сохраняться при перезагрузке и (2) даже после полного отключения издателя от сети.

  • Настраиваемые подписки может менять любой клиент настройки конфигурации с правами записи для настроек подписки. Динамические подписки можно изменять лишь вызовами RPC от исходного подписчика или путём изменения данных конфигурации, указываемых подпиской.

Отметим, что в одной подписке не смешиваются динамические и настраиваемые операции. В частности, настраиваемую подписку нельзя изменить или удалить с использованием RPC, заданных в этом документе. Динамическую подписку нельзя напрямую изменить или удалить операциями настройки конфигурации. Однако можно выполнить операцию настройки, опосредованно влияющую на динамическую подписку. При смене значения настроенного фильтра, указанного имеющейся динамической подпиской, передаваемые записи событий могут смениться.

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

Издатель может прервать динамическую подписку в любой момент, а также может приостановить отправку уведомлений для любой динамической подписки и одного или нескольких получателей настраиваемой подписки. Такое прекращение или приостановка определяется самим издателем.

1.4. Отличия от RFC 5277

Этот документ предназначен для обеспечения расширенных возможностей подписки, исходно заданной в [RFC5277]. Важно понимать, что используется повторно или заменено, особенно при расширении имеющихся реализаций на основе [RFC5277]. Основные различия между этими двумя документами указаны ниже.

  • Этот документ задаёт независимую от транспорта возможность, а [RFC5277] привязан к NETCONF.

  • Для новых операций применяется описанная здесь модель данных вместо модели из параграфа 3.4 в [RFC5277].

  • Операции RPC из этого документа заменяют <create-subscription> из раздела 4 в [RFC5277].

  • Применяется сообщение <notification> из раздела 4 в [RFC5277].

  • Содержимое потока событий NETCONF идентично в обоих случаях.

  • Издатель может одновременно реализовать Notification Management Schema и RPC из [RFC5277] и этого документа.

  • В отличие от [RFC5277], этот документ позволяет в одной транспортной сессии смешивать уведомления и RPC из разных подписок.

  • Время остановки (stop-time) для подписки можно задать как часть воспроизведения (replay) уведомления. Это поддерживает возможность, аналогичную параметру <stopTime> из [RFC5277]. Однако в данной спецификации параметр stop-time может применяться и без воспроизведения.

2. Решение

В соответствии с обзором в параграфе 1.3 этот раздел подробно описывает общий контекст, конечные автоматы и подсистемы, которые могут быть собраны для обеспечения возможности подписки на события от издателя.

2.1. Потоки событий

Поток событий — это именованный элемент у издателя, представляющий постоянно обновляемый набор записей о событиях, заданных в YANG. Запись о событии является воплощением оператора YANG notification. Если оператор notification задан как потомок узла данных, экземпляр включает иерархию узлов, указывающую узел данных в хранилище (параграф 7.16.2 в [RFC7950]). Каждый поток событий доступен для подписки. Идентификация способов a) определения потока событий (кроме потока NETCONF), b) определения и генерации записей о событиях и c) привязки записей к потоку событий выходят за рамки этого документа.

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

Поскольку заданные в YANG записи о событиях создаются системой, они могут быть привязаны к одному или нескольким потокам. Запись о событии распространяется подписчикам, когда (1) подписка включает указанный поток и (2) фильтры подписки не исключают эту запись для получателя.

Могут применяться правила управления доступом для исключения записей о событиях из потока событий при отсутствии доступа на чтение. В параграфе 3.4.6 [RFC8341] приведён пример такого контроля. Отметим, что в соответствии с параграфом 2.7 этого документа, подписка на уведомления о смене состояния никогда не фильтруется.

Если для записей о событии в потоке не задано правил контроля доступа, получателю должен разрешаться доступ ко всем записям. Если права доступа для подписчика меняются во время действия подписки и доступ к потоку событий становится невозможным, подписка должна прерываться.

Записи о событиях недопустимо доставлять получателям с изменением порядка из включения в поток событий.

2.2. Фильтры потоков событий

Этот документ задаёт расширяемый механизм фильтрации. Фильтр является логическим тестом, помещаемым в запись о событии. Результат false ведёт к исключению записи из доставки получателю. Фильтр никогда не вырезает сведений из записи о событии до того, как запись будет инкапсулирована в уведомление. Поддерживается два необязательных варианта синтаксиса фильтрации потоков на основе [XPATH] и ветвей (субдеревьев) [RFC6241].

Если в подписке не задан фильтр потока событий, получателю передаются все записи из потока.

2.3. QoS

Этот документ предоставляет несколько параметров качества обслуживания (Quality of Service или QoS), задающих обработку подписки по отношению к иному трафику между издателем и получателем.

  • Маркировка dscp для дифференцированной приоритизации уведомлений при передаче через сеть.

  • «Вес» для выделения подписке пропускной способности пропорциональной ему среди других подписок.

  • «Зависимость» (dependency) от других подписок.

Если издатель поддерживает свойство (feature) dscp, подписка с листом dscp должна приводить к соответствующей маркировке DSCP3 [RFC2474] в заголовке IP каждого уведомления, включая уведомления о смене состояния. Издатель должен соблюдать маркировку DSCP для исходящего от него трафика подписки.

Для разных кодов DSCP нужны разные транспортные соединения, поэтому при использовании TCP издатель с поддержкой свойства dscp должен гарантировать, что уведомления из подписки передаются в одной транспортной сессии TCP, где весь трафик подписки использует значение листа dscp. Если это невозможно гарантировать, любой вызов RPC establish-subscription следует отклонять с ошибкой dscp-unavailable.

Для параметра weighting при одновременном извлечении из очереди уведомлений из нескольких подписок для получателя издатель должен выделить для каждой подписки пропускную способность, пропорциональную «весу» этой подписки. Поддержка weighting не обязательна для издателя и зависит от свойства (feature) qos.

Если для подписки установлен параметр dependency, любые буферизованные уведомления, содержащие события, выбранные родительской подпиской, должны выталкиваться из очереди (dequeue) раньше уведомлений зависимой подписки. Если уведомления зависят друг от друга, первыми должны выходить из очереди те, которые были в ней дольше. Если dependency в RPC ссылается не несуществующую или больше не доступную подписку, зависимость (dependency) должна удаляться без уведомления. Возможность dependency необязательна для издателя и её поддержка указывается свойством (feature) qos.

Параметры dependency и weighting будут соблюдаться и применяться только для подписок с одинаковым значением листа dscp.

Имеются другие типы перегрузки возможностей (capacity) издателя, которые данная спецификация не рассматривает. Например, не обсуждается приоритизация подписок при перегрузке CPU у издателя. При выборе реализации такие соображения необходимо учитывать.

2.4. Динамическая подписка

Для управления динамическими подписками служат операции протокола (в форме RPC в соответствии с параграфом 7.14 [RFC7950]) выполняемые по отношению к элементам издателя (целям). Эти RPC разрабатывались с возможностью расширения, чтобы их можно было выполнять для целей подписки вне потока событий. Примеры таких дополнений RPC приведены в моделе данных YANG, представленной в [RFC8641].

2.4.1. Конечный автомат динамической подписки

На рисунке 1 показан конечный автомат издателя для динамической подписки, каждое состояние которого указано отдельным блоком. Важно отметить, что подписка не существует у издателя, пока не будет воспринят вызов RPC establish-subscription. Простого запроса подписчика недостаточно для того, чтобы подписка была видна извне. Состояния start и end показаны для отражения событий начала и завершения подписки.

                 .........
                 : start :
                 :.......:
                     |
            establish-subscription
                     |
                     |   .-------modify-subscription--------.
                     v   v                                  |
               .-----------.                          .-----------.
    .--------. |получатель |--недостат. CPU и полосы->|получатель |
modify-       '| активен   |                          |приостанов-|
subscription   |           |<--достат. CPU и полосы --|лен        |
    ---------->'-----------'                          '-----------'
                     |                                      |
          delete/kill-subscription                     delete/kill-
                     |                                 subscription
                     v                                      |
                 .........                                  |
                 :  end  :<---------------------------------'
                 :.......:

Рисунок 1. Конечный автомат издателя для динамической подписки.


Ниже указаны интересные аспекты конечного автомата.

  • Успешный вызов RPC establish-subscription или modify-subscription переводит подписку в состояние active.

  • Отказ RPC modify-subscription не меняет состояния подписки и потоковые обновления не меняются.

  • RPC delete-subscription или kill-subscription завершают подписку, как и достижение stop-time.

  • Издатель может приостановить подписку при нехватке ресурсов CPU или пропускной способности для её обслуживания. Это анонсируется подписчику в уведомлении о смене состояния subscription-suspended.

  • Подписчик может изменить приостановленную подписку (например, в попытке использовать меньше ресурсов) и успешное изменение возвращает подписку в состояние active.

  • Даже без запроса modify-subscription издатель может вернуть подписку в состояние active при наличии достаточных ресурсов. Это анонсируется подписчику в уведомлении о смене состояния subscription-resumed.

2.4.2. Организация динамической подписки

RPC establish-subscription позволяет подписчику запросить создание подписки. Операция принимает на входе ряд параметров, описанных ниже.

  • Имя потока — stream, указывающее целевой поток событий, к которому применяется подписка.

  • Фильтр событий потока, который может сокращать число выталкиваемых подписчику записей.

  • Если применяемый RPC использует несколько форм кодирования, параметр encoding задаёт тип кодирования. При отсутствии этого параметра должно применяться кодирование RPC.

  • Необязательное время остановки подписки — stop-time. При отсутствии stop-time уведомления будут передаваться до момента прерывания подписки.

  • Необязательный параметр replay-start-time, значение которого должно быть в прошлом, указывающий что в подписке нужно воспроизвести события с этого момента. Воспроизведение событий описано в параграфе 2.4.2.1. При отсутствии replay-start-time подписка начинается с момента её организации.

Если издатель может выполнить запрос establish-subscription, он возвращает идентификатор подписки и незамедлительно запускает поток уведомлений о событиях.

Ниже приведена диаграмма дерева establish-subscription. Объекты дерева представлены в модуле YANG (раздел 4).

       +---x establish-subscription
          +---w input
          |  +---w (target)
          |  |  +--:(stream)
          |  |     +---w (stream-filter)?
          |  |     |  +--:(by-reference)
          |  |     |  |  +---w stream-filter-name
          |  |     |  |          stream-filter-ref
          |  |     |  +--:(within-subscription)
          |  |     |     +---w (filter-spec)?
          |  |     |        +--:(stream-subtree-filter)
          |  |     |        |  +---w stream-subtree-filter?   <anydata>
          |  |     |        |          {subtree}?
          |  |     |        +--:(stream-xpath-filter)
          |  |     |           +---w stream-xpath-filter?
          |  |     |                   yang:xpath1.0 {xpath}?
          |  |     +---w stream                               stream-ref
          |  |     +---w replay-start-time?
          |  |             yang:date-and-time {replay}?
          |  +---w stop-time?
          |  |       yang:date-and-time
          |  +---w dscp?                                      inet:dscp
          |  |       {dscp}?
          |  +---w weighting?                                 uint8
          |  |       {qos}?
          |  +---w dependency?
          |  |       subscription-id {qos}?
          |  +---w encoding?                                  encoding
          +--ro output
             +--ro id                            subscription-id
             +--ro replay-start-time-revision?   yang:date-and-time
                     {replay}?

Рисунок 2. Диаграмма дерева RPC establish-subscription.

Издатель может отвергнуть RPC establish-subscription по многим причинам, как описано в параграфе 2.4.6. Передаваемое в результате сообщение об ошибке RPC может включать детали входных параметров, позволяющие организовать подписку следующим вызовом RPC establish-subscription. Такие советы должны передаваться в контейнере yang-data establish-subscription-stream-error-info, включённом в сообщение об ошибке RPC.

Ниже представлено дерево yang-data establish-subscription-stream-error-info. Объекты этого дерева описаны в модуле YANG (раздел 4).

       yang-data establish-subscription-stream-error-info
         +--ro establish-subscription-stream-error-info
            +--ro reason?                   identityref
            +--ro filter-failure-hint?      string

Рисунок 3. Диаграмма дерева yang-data establish-subscription-stream-error-info.

2.4.2.1. Запрос воспроизведения записей о событиях

Воспроизведение позволяет организовать подписку, способную передать записи о событиях недавнего прошлого. Иными словами, при инициализации подписки передаются все записи целевого потока событий, которые соответствуют фильтру, произошли после replay-start-time и до stop-time, если имеется stop-time. Завершение записей о прошлых событиях указывается сменой состояния подписки на replay-completed. Затем могут следовать любые записи о событиях после организации подписки. Для конкретной подписки все записи событий доставляются п порядке размещения в потоке событий.

Функция воспроизведения необязательна и её поддержка зависит поддержки потока событий в том или ином журнале (log). Этот документ не ограничивает размер и форму журнала, место его размещения у издателя, условия очистки.

Включение replay-start-time в RPC establish-subscription указывает запрос воспроизведения. Если replay-start-time содержит значение раньше, чем поддерживается в хранящейся истории событий, подписка воспринимается, а в replay-start-time-revision возвращаемого отклика должно указываться фактическое время начала воспроизведения. В подписку на воспроизведение может включаться параметр stop-time, которые может указывать время до текущего момента, но должен указывать время после replay-start-time. Если replay-start-time указывает время после указанного в записях буфера воспроизведения, издатель должен передать уведомления replay-completed сразу после отклика об успехе RPC establish-subscription.

Если поток событий поддерживает воспроизведение, лист replay-support присутствует в записи списка /streams/stream для потока событий. Не предполагается, что поток событий с поддержкой воспроизвдения имеет неограниченную возможность сохранять уведомления для любого последующего запроса на воспроизведение. Чтобы оценить временные рамки доступных для воспроизведения событий, подписчик может считать значения листьев replay-log-creation-time и replay-log-aged-time, показанные на рисунке 18 для дерева YANG и в разделе 4 с определением элементов модуля YANG. Фактический размер журнала воспроизведения в каждый момент времени зависит от издетеля. Параметры управления журналом воспроизведения выходят за рамки этого документа.

2.4.3. Изменение динамической подписки

Операция modify-subscription позволяет изменить условия имеющейся динамической подписки. Подписку можно менять неограниченное число раз. Изменение динамической подписки возможно лишь через RPC с использованием транспортной сессии, соединяющей с подписчиком. Если издатель принимает запрос на изменение подписки, он подтверждает это подписчику и сразу же начинает передавать сообщения в соответствии с новыми условиями.

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

Ниже приведено дерево для modify-subscription. Объекты дерева описаны в модуле YANG (раздел 4).

       +---x modify-subscription
          +---w input
             +---w id
             |       subscription-id
             +---w (target)
             |  +--:(stream)
             |     +---w (stream-filter)?
             |        +--:(by-reference)
             |        |  +---w stream-filter-name
             |        |          stream-filter-ref
             |        +--:(within-subscription)
             |           +---w (filter-spec)?
             |              +--:(stream-subtree-filter)
             |              |  +---w stream-subtree-filter?   <anydata>
             |              |          {subtree}?
             |              +--:(stream-xpath-filter)
             |                 +---w stream-xpath-filter?
             |                         yang:xpath1.0 {xpath}?
             +---w stop-time?
                     yang:date-and-time

Рисунок 4. Дерево modify-subscription RPC.

Если издатель принимает запрошенные изменения приостановленной в данный момент подписки, подписка незамедлительно возобновляется (т. е. возвращается в состояние active). Издатель может сразу же приостановить измененную модписку, передав уведомление subscription-suspended до отправки какой-либо записи обновления.

Если издатель отвергает запрос RPC, состояние подписки не изменяется, т. е. запрос не имеет влияния. Отклонение RPC по любой причине указывается ошибкой RPC, как указано в параграфе 2.4.6. Содержимое отклика с ошибкой RPC может включать советы, которые (при их принятии) могут обеспечить успех следующей подписки. Эти советы должны передаваться в контейнере yang-data modify-subscription-stream-error-info, помещаемом в отклик об ошибке RPC.

Ниже приведено дерево для modify-subscription-stream-error-info RPC yang-data. Объекты дерева описаны в модуле YANG (раздел 4).

       yang-data modify-subscription-stream-error-info
         +--ro modify-subscription-stream-error-info
            +--ro reason?                identityref
            +--ro filter-failure-hint?   string

Рисунок 5. Дерево modify-subscription-stream-error-info RPC yang-data.

2.4.4. Удаление динамической подписки

Операция delete-subscription позволяет отменить имеющуюся подписку. Если издатель принимает и подтверждает запрос, ему недопустимо предавать какие-либо ведомления для подписки.

Ниже приведено дерево для delete-subscription. Объекты дерева описаны в модуле YANG (раздел 4).

       +---x delete-subscription
          +---w input
             +---w id     subscription-id

Рисунок 6. Дерево delete-subscription RPC.

Удаление динамической подписки возможно лишь через RPC с использованием транспортной сессии, соединяющей с подписчиком. Настраиваемую подписку нельзя удалить с помощью RPC.

2.4.5. Уничтожение динамической подписки

Операция kill-subscription позволяет оператору прервать динамическую подписку, не связанную с транспортной сессией, используемой RPC. Издатель должен прервать любую динамическую подписку, указанную параметром id в запросе RPC, если такая подписка существует.

Настраиваемую подписку нельзя удалить с помощью этого вызова RPC, но можно удалить её обычной операцией настройки. Издетели должны отвергать любые RPC, пытающиеся уничтожить настраиваемую подписку.

Ниже приведено дерево для kill-subscription. Объекты дерева описаны в модуле YANG (раздел 4).

       +---x kill-subscription
          +---w input
             +---w id     subscription-id

Рисунок 7. Дерево kill-subscription RPC.

2.4.6. Отказы RPC

При неудачном выполнении RPC издатель возвращает связанные с этим сведения как часть отклика RPC об ошибке. Обработка ошибок транспортного уровня должна выполняться до описанной в этом параграфе обработки ошибок RPC. Во всех случаях сведения об ошибке RPC, возвращённые издателем, будут использовать имеющиеся структуры RPC транспортного уровня, такие как можно видеть в NETCONF (Приложение A к [RFC6241]) или RESTCONF (параграф 7.1 в [RFC8040]). Эти структуры должны обеспечивать кодирование связанных с подписками ошибок, указанных ниже и определённых в представленной здесь модели данных YANG.

В результате такого разнообразия способ кодирования ошибок подписки в отклике RPC об ошибке зависит от транспорта. Действительные ошибки, которые могут возникать для каждого типа RPC, указаны ниже.

 

establish-subscription

modify-subscription

delete-subscription

kill-subscription

dscp-unavailable

filter-unsupported

no-such-subscription

no-such-subscription

encoding-unsupported

insufficient-resources

filter-unsupported

no-such-subscription

insufficient-resources

replay-unsupported

 

Пример основанного на NETCONF отклика с сообщением об ошибке из приведённого списка можно найти в отклике на ошибку no-such-subscription, представленном на рисунке 10 в [RFC8640].

Имеется один финальный набор независимых от транспорта элементов для ошибок RPC, включённых в определённую здесь модель данных YANG — 3 структуры yang-data, позволяющие издателю предоставить получателям любые сведения об ошибке, которые не помещаются в имеющиеся структуры RPC транспортных уровней.

  1. Структура establish-subscription-stream-error-info должна возвращаться с заполненным листом reason, если причина ошибки не включена где-то в транспортной части отклика от отказе RPC establish-subscription. Структура должна передаваться, если включены советы по преодолению ошибки RPC.

  2. Структура modify-subscription-stream-error-info должна возвращаться с заполненным листом reason, если причина ошибки не включена где-то в транспортной части отклика от отказе RPC modify-subscription. Структура должна передаваться, если включены советы по преодолению ошибки RPC.

  3. Структура delete-subscription-error-info должна возвращаться с заполненным листом reason, если причина ошибки не включена где-то в транспортной части отклика от отказе RPC delete-subscription или kill-subscription.

2.5. Настраиваемая подписка

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

Настраиваемые подписки имеют ряд отличий от динамических подписок:

  • сохранение после перезагрузки издателя;

  • сохранение при недоступности транспорта;

  • возможность передавать уведомления не одному получателю (получатели не знают друг о друге).

Поддержка настраиваемой подписки не обязательна для издателей и указывается анонсированием свойства configured. Для получателя настраиваемой подписки необязательна поддержка динамической подписки. Однако, если для настраиваемой подписки требуется воспроизведение пропущенных записей о событиях, получателю настоятельно рекомендуется поддерживать динамическую подписку, которая позволяет организовать повтор пропущенных записей.

В дополнение к описанным в параграфе 2.4.2 параметрам динамической подписки для настравиваемых подписок доступны указанные ниже параметры.

  • Параметр transport указывает транспортный протокол, используемый для всех получателей подписки.

  • Один или несколько получателей записей о событиях, указываемых по именам (name).

  • Необязательные параметры, указывающие точку выхода трафика от издателя:

    • source-interface указывает выходной интерфейс издателя (поддержка этого параметра не обязательна и анонсируется свойством interface-designation);

    • source-address указывает адрес IP для указания в уведомлениях, отправляемых получателям;

    • source-vrf указывает экземпляр виртуальной маршрутизации и пересылки (Virtual Routing and Forwarding или VRF) для отправки уведомлений получателям, определённый в [RFC8529] (поддержка VRF не обязательна для издателя и анонсируется свойством supports-vrf).

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

Дерево, включающее эти параметры, приведено на рисунке 20 в параграфе 3.3, а параметры описаны в модуле YANG (раздел 4).

2.5.1. Конечный автомат настраиваемой подписки

На рисунке 8 показан конечный автомат издателя для настраиваемой подписки, описывающий 3 состояния (valid, invalid, concluded) и переходы между ними. Указаны также начальное (start) и конечное (end) состояния для создания и удаления подписки. Создание или изменение настраиваемой подписки вызывает оценку издетелем возможности подписки (valid или invalid) на основании своих книтериев. Если подписка возможна (valid), она начинает работать — линия (1) на рисунке.

Подиска может перейти из состояния valid в состояние invalid одним из двух способов. Во-первых, это может быть изменение, делающее подписку непригодной — (2) на рисунке. Во-вторых, издатель может решить, что подписка больше не поддерживается. Это может быть связано с неожиданным, но существенным ростом числа записей в потоке событий, снижением возможностей CPU, указанием более сложного фильтра или другими подписками, потребляющими много ресурсов — (3) на рисунке. В любом случае передаётся уведомление subscription-terminated всем получателям с состоянием active или suspended. Подписчик с состоянием valid может быть переведен в состояние concluded по достижении времени остановки — (5). В этом случае передаётся уведомление subscription-concluded всем получателям с состоянием active или suspended. Подписка может быть уделена через настройку — (4).

 .........
 : start :-.
 :.......: |
      create  .---modify-----.----------------------------------.
           |  |              |                                  |
           V  V          .-------.         .......         .---------.
  .----[evaluate]--no--->|invalid|-delete->: end :<-delete-|concluded|
  |                      '-------'         :.....:         '---------'
  |-[evaluate]--no-(2).      ^                ^                 ^
  |        ^          |      |                |                 |
 yes       |          '->unsupportable      delete           stop-time
  |      modify         (subscription-   (subscription-   (subscription-
  |        |             terminated*)     terminated*)      concluded*)
  |        |                 |                |                 |
 (1)       |                (3)              (4)               (5)
  |   .---------------------------------------------------------------.
  '-->|                         valid                                 |
      '---------------------------------------------------------------'

 В прямоугольниках из точек показано добавление или удаление подписки
 через конфигурацию, в прямоугольнкиах из линий - состояния подписки.
 [evaluate] указывает принятие решения о возможности подписки.
 * указывает уведомление о смене состояния подписки.

Рисунок 8. Конечный автомат издателя для настраиваемой подписки.


Для действительной (valid) подписки издатель пытается соединиться со всеми получателями и доставлять им уведомления. На рисунке 9 показан конечный автомат получателя настраиваемой подписки, который полностью содержится в конечном автомате настраиваемой подписки и актуален лишь для подписок в состоянии valid.

.-----------------------------------------------------------------.
|                         valid                                   |
|   .----------.                           .------------.         |
|   | receiver |---timeout---------------->|  receiver  |         |
|   |connecting|<----------------reset--(c)|disconnected|         |
|   |          |<-transport                '------------'         |
|   '----------'  loss,reset------------------------------.       |
|      (a)          |                                     |       |
|  subscription-   (b)                                   (b)      |
|  started*    .--------.                             .---------. |
|       '----->|        |(d)-недостаточно CPU,------->|         | |
|              |receiver|    переполнение буферов     |receiver | |
| subscription-| active |                             |suspended| |
|   modified*  |        |<----CPU, достат. полосы,-(e)|         | |
|        '---->'--------'     subscription-modified*  '---------' |
'-----------------------------------------------------------------'

  Прямоугольники со словом receiver указывают возможные состояния
  отдельного получателя действующей настраиваемой подписки.
  * указывает уведомление о смене состояния подписки.

Рисунок 9. Конечный автомат получателя настраиваемой подписки.


Когда настраиваемая подписка перевый раз переходит в состояние valid, лист state для каждого получателя инициализируется значением connecting. Если транспортная связность недоступна ни для одного из получателей и имеются какие-либо сообщения для доставки, организуется транспортная сессия (например, в соответствии с [RFC8071]). Получатель переводится в состояние active, когда ему доставлено уведомление о смене состояния подписки на subscription-started — (a). Записи о событиях передаются лишь активным получателям. Получатели настраиваемой подписки остаются активными у издателя, если (1) транспортная связность с получателем имеется и (2) записи о событиях не были отброшены из-за ограничений передачи у издателя. Получатель настраиваемой статистики должен переводиться в состояние connecting, если получатель сброшен действием reset -(b), (c). Дополнительные сведения о действии reset приведены в параграфе 2.5.5. Если транспортную связность не удаётся обеспечить в состоянии connecting, получатель может быть переведен в состояние disconnected.

Получатель настраиваемой подписки должен переводиться в состояние suspended, если между ним и издателем имеется транспортная связность, но (1) при доставке уведомлений возник отказ в результате исчерпания возможностей буферов или (2) уведомления для этого получателя не удалось из-за нехватки ресурсов CPU (d). Это указывается получателю уведомлением о смене состояния подписки subscription-suspended.

Получатель настраиваемой подписки должен возвращаться в состояние active из suspended, когда созданы уведомления, пропускной способности достаточно для обслуживания уведомлений и получателю было успешно передано уведомление о смене состояния подписки subscription-resumed или subscription-modified — (e). Выбор уведомления о смене состояния подписки определяется наличием изменений в подписке в период её приостановки.

Изменить настраиваемую подписку можно в любое время. Уведомление о смене состояния подписки subscription-modified передаётся всем активным получателям, а сразу вслед за ним передаются уведомления, соответствующие новым параметрам. Приостановленные получатели тоже информируются об изменении. Однако эти уведомления будут ждать завершения приостановки для этого получателя или получателей.

Описанные выше уведомления отражены в RPC и определениях, заданных этим документом. Следует отметить, что эти RPC и уведомления предназначены для возможности расширения и разрешают подписки для целей, отличающихся от потока событий. Например, модуль YANG из раздела 5 в [RFC8641] дополняет /sn:modify-subscription/sn:input/sn:target.

2.5.2. Организация настраиваемой подписки

Настраиваемые подписки организуются с помощью операций настройки для верхнего уровня ветви subscriptions.

По причине отсутствия явной привязки к имеющейся транспортной сессии операции настройки должны включать дополнительные параметры по сравнению с динамической подпиской. Эти параметры идентифицируют каждого получателя, способ соединения с ним и, возможно, привязку к определённому выходному интерфейсу издателя. Параметры зависящей от получателя транспортной связности должны настраиваться через определяемые транспортом дополнения (augment) к этой спецификации (2.5.7. Транспортная связность для настраиваемой подписки).

После организации подписки издатель сразу же передаёт каждому получателю уведомление о смене состояния подписки subscription-started. Вполне возможно, что после настройки, перезагрузки или даже работы в установившемся состоянии транспортная сессий может стать недоступной получателю. В таком случае при наличии данных для доставки в активной подписке применяются зависящие от транспорта операции «звонка домой» (call home) [RFC8071] для организации соединения. Когда транспорт будет доступен, уведомления можно вытолкнуть получателю.

Для активных настраиваемых подписок разрешается буферизовать записи о событиях даже после отправки уведомления subscription-started. Однако при потере событий (а не просто задержке) из-за исчерпания буфера воспроизведения должно передаваться новое уведомление subscription-started, указывающее разрыв в записях.

Пример создания подписки с помощью операций настройки по протоколу NETCONF приведён в Приложении A.

2.5.3. Изменение настраиваемой подписки

Настраиваемые подписки можно изменять конфигурационными операциями применительно к ветви subscriptions.

Если изменение добавляет получателей, для них устанавливается состояние connecting. При удалении получателя ему передаётся уведомление о смене статуса подписки subscription-terminated, если он был активен или приостановлен.

Если изменение влияет на правила для подписки, издатель передаёт активным получателям уведомление subscription-modified. Для приостановленных получателей такое уведомление задерживается до момента восстановления подписки. Отметим, что в этом случае уведомление subscription-modified сообщает получателю о возобновлении подписки, поэтому передавать дополнительно уведомление subscription-resumed не требуется. Если во время приостановки произошло несколько изменений, получателю требуется передавать лишь уведомление subscription-modified, описывающее последнее изменение.

2.5.4. Удаление настраиваемой подписки

Подписчиков можно удалить с помощью операций настройки применительно к ветви верхнего уровня subscriptions.

Сразу после удаления подписки издатель передаёт всем её получателям уведомление об этом (subscription-terminated).

2.5.5. Сброс получателя настраиваемой подписки

Возможны случаи, когда настраиваемую подписку для получателя требуется сбросить (reset). Это выполняется с помощью действия reset в модуле YANG (/subscriptions/subscription/receivers/receiver/reset). Действие может быть полезно при тайм-ауте издателя для попытки связаться с получателем. При таком сбросе инициируется транспортная сессия, если это требуется, и передаётся новое уведомление subscription-started. Действие не влияет на транспортную связность, если требуемое соединение уже имеется.

2.5.6. Воспроизведение для настраиваемой подписки

Возможно воспроизведение (повтор) для настраиваемой подписки, выполняемое через конфигурацию её объекта configured-replay. Установка этого объекта включает потоковую передачу буферизованных записей потока событий подписки с момента последнего перезапуска издателя каждому настроенному получателю.

Воспроизведение записей о событиях, созданных с момента перезапуска, полезно. Это позволяет передать получателю записи о событиях, созданные до организации транспортного соединения с ним. Установка времени перезапуска как стартовой точки воспроизведения позволяет исключить повтор записей о событиях, созданных до перезапуска. Это также гарантирует, что каждому получателю будут переданы одни и те же записи, независимо от скорсти транспортного соединения с ним. Установка времени перезапуска в качестве стартовой точки воспроизведения позволяет чётко задать временные рамки.

В результате при активизации любого получателя настраиваемой подписки буферизованные записи будут переданы ему сразу после уведомления subscription-started. Если издатель знает последнюю переданную получателю запись и не перезапускался, первой воспроизводимой записью будет следующая запись, прошедшая фильтр отбора. В иных случаях первой будет запись, соответствующая фильтру отбора, следующая за самым поздним из моментов replay-log-creation-time, replay-log-aged-time или времени последней загрузки издателя. Листья replay-log-creation-time и replay-log-aged-time описаны в параграфе 2.4.2.1. Время последней загрузки издателя гарантирует отсутствие дубликатов записей из предшествующего перезагрузке периода.

Вполне возможно желание получателя воспроизвести записи из потока событий до последнего перезапуска издателя. Если такие записи имеются и настроено воспроизведение, издатель должен передать время записи о событии, непосредственно предшествующее replay-start-time в листе replay-previous-event-time. Благодаря наличию replay-previous-event-time, получатель будет знать, что имеются события, записанные до перезапуска. Кроме того, если получатель уже принимал записи о событиях с тем же идентификатором подписки, он может определить интервал времени для записей о событиях, которые не были получены. Зная это, получатель может использовать динамическую подписку для извлечения любых событий, помещенных в поток перед последним перезапуском.

Остальные функции воспроизведения соврадают с описанными в параграфе 2.4.2.1 для динамической подписки.

2.5.7. Транспортная связность для настраиваемой подписки

Эта спецификация не зависит от транспорта, однако для поддержки настраиваемой подписки зачастую нужна транспортная связность и параметры её организации зависят от транспорта. Поэтому модуль YANG, описанный в разделе 4, не может напрямую задавать и раскрывать эти транспортные параметры.

Реализации должны поддерживать процесс организации соединений, для чего в заданную этим документом модель данных YANG включён узел, куда можно добавить (augment) зависящие от транспорта параметры для отдельного получателя (/subscriptions/subscription/receivers/receiver). Добавление транспортных параметров в этот узел позволяет разработчикам включать объекты YANG, требуемые для поддержки процесса организации соединений.

В результате издатель, поддерживающий свойство configured, должен также поддерживать хотя бы одну модель данных YANG, дополняющую транспортные параметры в /subscriptions/subscription/receivers/receiver. Пример такого дополнения приведён в Приложении A.

2.6. Доставка записей о событиях

После организации подписки (динамической или настраиваемой) издатель передаёт поток записей о событиях в уведомлениях в соответствии с условиями подписки. Для динамической подписки уведомления передаются в сессии, использованной для организации подписки. Для настраиваемой подписки уведомления передаются через соединения, заданные транспортом и каждым получателем подписки.

Уведомление передаётся получателю, если запись о событии не заблокирована фильтром или контролем доступа для получателя. Уведомление должно включать объект <eventTime>, как указано в разделе 4 [RFC5277]. Этот объект <eventTime> должен размещаться на верхнем уровне структурированной записи YANG о событии.

Ниже приведён пример XML [W3C.REC-xml-20081126], заимствованный из параграфа 4.2.10 в [RFC7950], который иллюстрирует корректное сообщение.

      <notification
             xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0">
          <eventTime>2007-09-01T10:00:00Z</eventTime>
          <link-failure xmlns="https://acme.example.com/system">
              <if-name>so-1/2/3.0</if-name>
              <if-admin-status>up</if-admin-status>
              <if-oper-status>down</if-oper-status>
          </link-failure>
      </notification>

Рисунок 10. Уведомление настраиваемой подписки.

В параграфе 2.2.1 [RFC5277] сказано, что уведомление передаётся подписчику, вызвавшему <create-subscription>. Этот документ интерпретирует заявление [RFC5277] более широко, позволяя передавать уведомления подписчику, вызвавшему establish-subscription или заданному в конфигурации подписчику , которому было отправлено уведомление subscription-started.

При старте или изменении динамической подписки вызовом establish-subscription или modify-subscription, соответственно, записи о событиях, соответствующие вновь применённому фильтру, недопустимо передавать, пока не будет отправлен отклик RPC.

При старте или изменении настраиваемой подписки записи о событиях, соответствующие вновь применённому фильтру, недопустимо передавать, пока не будет отправлен отклик subscription-started или subscription-modified, соответственно.

2.7.Уведомления об изменении состояния подписки

В дополнение к отправке получателям записей о событиях издатель должен передавать уведомления о смене статуса подписки при возникновении событий, связанных с управлением подпиской.

Уведомления о смене состояния подписки отличаются от других уведомлений тем, что они не включаются в поток событий. Вместо этого уведомления включаются (в соответствии с этим разделом) в последовательность уведомлений, передаваемых конкретному получателю. Уведомления о смене статуса подписки не могут фильтроваться или отбрасываться и доставляются лишь получателя, для которых статус подписки изменился. Уведомления о смене состояния подписки легко отличить от других уведомлений по расширению YANG subscription-state-notif, служащему для пометки уведомлений об изменении состояния подписки.

В последующих параграфах описаны все уведомления о смене состояния подписки.

2.7.1. subscription-started

This notification indicates that a configured subscription has started, and event records may be sent. Included in this subscription state change notification are all the parameters of the subscription, except for (1) transport connection information for one or more receivers and (2) origin information indicating where notification messages will egress the publisher. Note that if a referenced filter from the «filters» container has been used in the subscription, the notification still provides the contents of that referenced filter under the «within-subscription» subtree.

Note that for dynamic subscriptions, no «subscription-started» notifications are ever sent.

Below is a tree diagram for «subscription-started». All objects contained in this tree are described in the YANG module in Section 4.

       +---n subscription-started {configured}?
          +--ro id
          |       subscription-id
          +--ro (target)
          |  +--:(stream)
          |     +--ro (stream-filter)?
          |     |  +--:(by-reference)
          |     |  |  +--ro stream-filter-name
          |     |  |          stream-filter-ref
          |     |  +--:(within-subscription)
          |     |     +--ro (filter-spec)?
          |     |        +--:(stream-subtree-filter)
          |     |        |  +--ro stream-subtree-filter?   <anydata>
          |     |        |          {subtree}?
          |     |        +--:(stream-xpath-filter)
          |     |           +--ro stream-xpath-filter?     yang:xpath1.0
          |     |                   {xpath}?
          |     +--ro stream                               stream-ref
          |     +--ro replay-start-time?
          |     |       yang:date-and-time {replay}?
          |     +--ro replay-previous-event-time?
          |             yang:date-and-time {replay}?
          +--ro stop-time?
          |       yang:date-and-time
          +--ro dscp?                                      inet:dscp
          |       {dscp}?
          +--ro weighting?                                 uint8 {qos}?
          +--ro dependency?
          |       subscription-id {qos}?
          +--ro transport?                                 transport
          |       {configured}?
          +--ro encoding?                                  encoding
          +--ro purpose?                                   string
                  {configured}?

Рисунок 11. Дерево уведомления subscription-started

2.7.2. subscription-modified

This notification indicates that a subscription has been modified by configuration operations. It is delivered directly after the last event records processed using the previous subscription parameters, and before any event records processed after the modification.

Below is a tree diagram for «subscription-modified». All objects contained in this tree are described in the YANG module in Section 4.

       +---n subscription-modified
          +--ro id
          |       subscription-id
          +--ro (target)
          |  +--:(stream)
          |     +--ro (stream-filter)?
          |     |  +--:(by-reference)
          |     |  |  +--ro stream-filter-name
          |     |  |          stream-filter-ref
          |     |  +--:(within-subscription)
          |     |     +--ro (filter-spec)?
          |     |        +--:(stream-subtree-filter)
          |     |        |  +--ro stream-subtree-filter?   <anydata>
          |     |        |          {subtree}?
          |     |        +--:(stream-xpath-filter)
          |     |           +--ro stream-xpath-filter?     yang:xpath1.0
          |     |                   {xpath}?
          |     +--ro stream                               stream-ref
          |     +--ro replay-start-time?
          |             yang:date-and-time {replay}?
          +--ro stop-time?
          |       yang:date-and-time
          +--ro dscp?                                      inet:dscp
          |       {dscp}?
          +--ro weighting?                                 uint8 {qos}?
          +--ro dependency?
          |       subscription-id {qos}?
          +--ro transport?                                 transport
          |       {configured}?
          +--ro encoding?                                  encoding
          +--ro purpose?                                   string
                  {configured}?

Рисунок 12. Дерево уведомления subscription-modified.

A publisher most often sends this notification directly after the modification of any configuration parameters impacting a configured subscription. But it may also be sent at two other times:

  1. If a configured subscription has been modified during the suspension of a receiver, the notification will be delayed until the receiver’s suspension is lifted. In this situation, the notification indicates that the subscription has been both modified and resumed.

  2. A «subscription-modified» subscription state change notification MUST be sent if the contents of the filter identified by the subscription’s «stream-filter-ref» leaf have changed. This state change notification is to be sent for a filter change impacting any active receivers of a configured or dynamic subscription.

2.7.3. subscription-terminated

This notification indicates that no further event records for this subscription should be expected from the publisher. A publisher may terminate the sending of event records to a receiver for the following reasons:

  1. Configuration that removes a configured subscription, or a «kill-subscription» RPC that ends a dynamic subscription. These are identified via the reason «no-such-subscription».

  2. A referenced filter is no longer accessible. This reason is

       identified by the "filter-unavailable" identity.

   3.  The event stream referenced by a subscription is no longer
       accessible by the receiver.  This reason is identified by the
       "stream-unavailable" identity.

   4.  A suspended subscription has exceeded some timeout.  This reason
       is identified by the "suspension-timeout" identity.

Each reason listed above derives from the «subscription-terminated-

   reason" base identity specified in the YANG data model in this
   document.

   Below is a tree diagram for "subscription-terminated".  All objects
   contained in this tree are described in the YANG module in Section 4.
       +---n subscription-terminated
          +--ro id        subscription-id
          +--ro reason    identityref

Рисунок 13. Диаграмма дерева уведомления subscription-terminated.

Note: This subscription state change notification MUST be sent to a dynamic subscription’s receiver when the subscription ends unexpectedly. This might happen when a «kill-subscription» RPC is successful or when some other event, not including reaching the subscription’s «stop-time», results in a publisher choosing to end the subscription.

2.7.4. subscription-suspended

This notification indicates that a publisher has suspended the

   sending of event records to a receiver and also indicates the
   possible loss of events.  Suspension happens when capacity
   constraints stop a publisher from serving a valid subscription.  The
   two conditions where this is possible are:
  1. «insufficient-resources», when a publisher is unable to produce the requested event stream of notification messages, and

  2. «unsupportable-volume», when the bandwidth needed to get

       generated notification messages to a receiver exceeds a
       threshold.

These conditions are encoded in the «reason» object. No further notifications will be sent until the subscription resumes or is terminated.

Below is a tree diagram for «subscription-suspended». All objects contained in this tree are described in the YANG module in Section 4.

       +---n subscription-suspended
          +--ro id        subscription-id
          +--ro reason    identityref

Рисунок 14. Дерево уведомления subscription-suspended.

2.7.5. subscription-resumed

This notification indicates that a previously suspended subscription has been resumed under the unmodified terms previously in place. Subscribed event records generated after the issuance of this subscription state change notification may now be sent.

Below is a tree diagram for «subscription-resumed». All objects contained in this tree are described in the YANG module in Section 4.

       +---n subscription-resumed
          +--ro id    subscription-id

Рисунок 15. Дерево уведомления subscription-resumed.

2.7.6. subscription-completed

This notification indicates that a subscription that includes a «stop-time» has successfully finished passing event records upon reaching that time.

Below is a tree diagram for «subscription-completed». All objects contained in this tree are described in the YANG module in Section 4.

       +---n subscription-completed {configured}?
          +--ro id    subscription-id

Рисунок 16. Дерево уведомления subscription-completed.

2.7.7. replay-completed

This notification indicates that all of the event records prior to the current time have been passed to a receiver. It is sent before any notification messages containing an event record with a timestamp later than (1) the «stop-time» or (2) the subscription’s start time.

If a subscription does not contain a «stop-time» or has a «stop-time» that has not been reached, then after the «replay-completed» notification has been sent, additional event records will be sent in sequence as they arise naturally on the publisher.

Below is a tree diagram for «replay-completed». All objects contained in this tree are described in the YANG module in Section 4.

       +---n replay-completed {replay}?
          +--ro id    subscription-id

Рисунок 17. Дерево уведомления replay-completed.

2.8. Мониторинг подписки

In the operational state datastore, the «subscriptions» container maintains the state of all dynamic subscriptions as well as all configured subscriptions. Using datastore retrieval operations [RFC8641] or subscribing to the «subscriptions» container (Section 3.3) allows the state of subscriptions and their connectivity to receivers to be monitored.

Each subscription in the operational state datastore is represented as a list element. Included in this list are event counters for each receiver, the state of each receiver, and the subscription parameters currently in effect. The appearance of the leaf «configured-subscription-state» indicates that a particular subscription came into being via configuration. This leaf also indicates whether the current state of that subscription is «valid», «invalid», or «concluded».

To understand the flow of event records in a subscription, there are two counters available for each receiver. The first counter is «sent-event-records», which shows the number of events identified for sending to a receiver. The second counter is «excluded-event-records», which shows the number of event records not sent to a receiver. «excluded-event-records» shows the combined results of both access control and per-subscription filtering. For configured subscriptions, counters are reset whenever the subscription’s state is evaluated as «valid» (see (1) in Figure 8).

Dynamic subscriptions are removed from the operational state datastore once they expire (reaching «stop-time») or when they are terminated. While many subscription objects are shown as configurable, dynamic subscriptions are only included in the operational state datastore and as a result are not configurable.

2.9. Поддержка модуля YANG ietf-subscribed-notifications

Publishers supporting this document MUST indicate support of the YANG module «ietf-subscribed-notifications» in the YANG library of the publisher. In addition, if supported, the optional features «encode-xml», «encode-json», «configured», «supports-vrf», «qos», «xpath», «subtree», «interface-designation», «dscp», and «replay» MUST be indicated.

3. Диаграммы деревьев модели YANG

This section contains tree diagrams for nodes defined in Section 4. For tree diagrams of subscription state change notifications, see Section 2.7. For the tree diagrams for the RPCs, see Section 2.4.

3.1. Контейнер streams

A publisher maintains a list of available event streams as operational data. This list contains both standardized and vendor-specific event streams. This enables subscribers to discover what streams a publisher supports.

Below is a tree diagram for the «streams» container. All objects contained in this tree are described in the YANG module in Section 4.

     +--ro streams
        +--ro stream* [name]
           +--ro name                        string
           +--ro description                 string
           +--ro replay-support?             empty {replay}?
           +--ro replay-log-creation-time    yang:date-and-time
           |       {replay}?
           +--ro replay-log-aged-time?       yang:date-and-time
                   {replay}?

Рисунок 18. Дерево контейнера streams.

3.2. Контейнер filters

The «filters» container maintains a list of all subscription filters that persist outside the lifecycle of a single subscription. This enables predefined filters that may be referenced by more than one subscription.

Below is a tree diagram for the «filters» container. All objects contained in this tree are described in the YANG module in Section 4.

     +--rw filters
        +--rw stream-filter* [name]
           +--rw name                           string
           +--rw (filter-spec)?
              +--:(stream-subtree-filter)
              |  +--rw stream-subtree-filter?   <anydata> {subtree}?
              +--:(stream-xpath-filter)
                 +--rw stream-xpath-filter?     yang:xpath1.0 {xpath}?

Рисунок 19. Дерево контейнера filters.

3.3. Контейнер subscriptions

The «subscriptions» container maintains a list of all subscriptions on a publisher, both configured and dynamic. It can be used to retrieve information about the subscriptions that a publisher is serving.

Below is a tree diagram for the «subscriptions» container. All objects contained in this tree are described in the YANG module in Section 4.

     +--rw subscriptions
        +--rw subscription* [id]
           +--rw id
           |       subscription-id
           +--rw (target)
           |  +--:(stream)
           |     +--rw (stream-filter)?
           |     |  +--:(by-reference)
           |     |  |  +--rw stream-filter-name
           |     |  |          stream-filter-ref
           |     |  +--:(within-subscription)
           |     |     +--rw (filter-spec)?
           |     |        +--:(stream-subtree-filter)
           |     |        |  +--rw stream-subtree-filter?   <anydata>
           |     |        |          {subtree}?
           |     |        +--:(stream-xpath-filter)
           |     |           +--rw stream-xpath-filter?
           |     |                   yang:xpath1.0 {xpath}?
           |     +--rw stream                               stream-ref
           |     +--ro replay-start-time?
           |     |       yang:date-and-time {replay}?
           |     +--rw configured-replay?                   empty
           |             {configured,replay}?
           +--rw stop-time?
           |       yang:date-and-time
           +--rw dscp?                                      inet:dscp
           |       {dscp}?
           +--rw weighting?                                 uint8 {qos}?
           +--rw dependency?
           |       subscription-id {qos}?
           +--rw transport?                                 transport
           |       {configured}?
           +--rw encoding?                                  encoding
           +--rw purpose?                                   string
           |       {configured}?
           +--rw (notification-message-origin)? {configured}?
           |  +--:(interface-originated)
           |  |  +--rw source-interface?
           |  |          if:interface-ref {interface-designation}?
           |  +--:(address-originated)
           |     +--rw source-vrf?
           |     |       -> /ni:network-instances/network-instance/name
           |     |       {supports-vrf}?
           |     +--rw source-address?
           |             inet:ip-address-no-zone
           +--ro configured-subscription-state?             enumeration
           |       {configured}?
           +--rw receivers
              +--rw receiver* [name]
                 +--rw name                      string
                 +--ro sent-event-records?
                 |       yang:zero-based-counter64
                 +--ro excluded-event-records?
                 |       yang:zero-based-counter64
                 +--ro state                     enumeration
                 +---x reset {configured}?
                    +--ro output
                       +--ro time    yang:date-and-time

Рисунок 20. Дерево контейнера subscriptions.

4. Модуль YANG для подписки на уведомления о событиях

This module imports typedefs from [RFC6991], [RFC8343], [RFC8341], [RFC8529], and [RFC8040]. It references [RFC6241], [XPATH] («XML Path Language (XPath) Version 1.0»), [RFC7049], [RFC8259], [RFC7950], [RFC7951], and [RFC7540].

<CODE BEGINS> file "ietf-subscribed-notifications@2019-09-09.yang"
module ietf-subscribed-notifications {
  yang-version 1.1;
  namespace "urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications";
  prefix sn;

  import ietf-inet-types {
    prefix inet;
    reference
      "RFC 6991: Common YANG Data Types";
  }
  import ietf-interfaces {
    prefix if;
    reference
      "RFC 8343: A YANG Data Model for Interface Management";
  }
  import ietf-netconf-acm {
    prefix nacm;
    reference
      "RFC 8341: Network Configuration Access Control Model";
  }
  import ietf-network-instance {
    prefix ni;
    reference
      "RFC 8529: YANG Data Model for Network Instances";
  }
  import ietf-restconf {
    prefix rc;
    reference
      "RFC 8040: RESTCONF Protocol";
  }
  import ietf-yang-types {
    prefix yang;
    reference
      "RFC 6991: Common YANG Data Types";
  }

  organization
    "IETF NETCONF (Network Configuration) Working Group";
  contact
    "WG Web:  <https:/datatracker.ietf.org/wg/netconf/> 
     WG List: <mailto:netconf@ietf.org> 

     Author:  Alexander Clemm
              <mailto:ludwig@clemm.org> 

     Author:  Eric Voit
              <mailto:evoit@cisco.com> 

     Author:  Alberto Gonzalez Prieto
              <mailto:alberto.gonzalez@microsoft.com> 

     Author:  Einar Nilsen-Nygaard
              <mailto:einarnn@cisco.com> 

     Author:  Ambika Prasad Tripathy
              <mailto:ambtripa@cisco.com>"; 
  description
    "Этот модуль задаёт модель данных YANG для описания подписки на
     записи о событиях и получения соответствующих уведомлений.

     Ключевые слова ДОЛЖНО, НЕДОПУСТИМО, ТРЕБУЕТСЯ, НУЖНО, НЕ НУЖНО, 
     СЛЕДУЕТ, НЕ СЛЕДУЕТ, РЕКОМЕНДУЕТСЯ, НЕ РЕКОМЕНДУЕТСЯ, МОЖНО,
     НЕОБЯЗАТЕЛЬНО в этом документе трактуются в соответствии с 
     BCP 14 (RFC 2119) (RFC 8174) тогда и только тогда, когда они
     указаны заглавными буквами, как показано здесь.

     Авторские права (Copyright (c) 2019) принадлежат IETF Trust и
     лицам, указанным как авторы. Все права защищены.

     Распространение и применение модуля в исходной или двоичной 
     форме с изменениями или без таковых разрешено в соответствии с
     лицензией Simplified BSD License, изложенной в параграфе 4.c
     IETF Trust's Legal Provisions Relating to IETF Documents
     (https://trustee.ietf.org/license-info). 

     Эта версия модуля YANG является частью RFC 8639, где правовые
     аспекты приведены более полно.";

  revision 2019-09-09 {
    description
      "Исходный выпуск.";
    reference
      "RFC 8639: A YANG Data Model for Subscriptions to
                 Event Notifications";
  }

  /*
   * Свойства (функции)
   */
  feature configured {
    description
      "Указывает поддержку настройки подписок.";
  }

  feature dscp {
    description
      "Указывает поддержку издателем возможности указывать код
       дифференцированного обслуживания (DSCP) в исходящих пакетах.";
  }

  feature encode-json {
    description
      "Указывает поддержку кодирования JSON для уведомлений.";
  }

  feature encode-xml {
    description
      "Указывает поддержку кодирования XML для уведомлений.";
  }

  feature interface-designation {
    description
      "Указывает, что издатель выполняется все взаимодействия с
       получателем в рамках настраиваемой подписки через один
       назначенный выходной интерфейс.";
  }

  feature qos {
    description
      "Указывает поддержку издателем абсолютной зависимости трафика
       одной подписки от другой, а также взвешенное распределение
       пропускной способности между подписками. Это относится к функциям
       качества обслуживания (QoS), позволяющим дифференцированно
       обрабатывать уведомления между издателем и получателями.";
  }

  feature replay {
    description
      "Указывает поддержку воспроизведения записи событий, которое
       позволяет передать поток записей о событиях в хронологическом
       порядке.";
  }

  feature subtree {
    description
      "Указывает поддержку фильтрации по ветвям дерева YANG.";
    reference
      "RFC 6241: Network Configuration Protocol (NETCONF),
                 Section 6";
  }

  feature supports-vrf {
    description
      "Указывает поддержку издателем конфигурации VRF для
       настраиваемых подписок. Поддержка VRF для динамических
       подписок не требует этой функции.";
    reference
      "RFC 8529: YANG Data Model for Network Instances,
                 Section 6";
  }
  feature xpath {
    description
      "Указывает поддержку фильтрации XPath.";
    reference
      "XML Path Language (XPath) Version 1.0
       (https://www.w3.org/TR/1999/REC-xpath-19991116)"; 
  }

  /*
   * Расширения
   */

  extension subscription-state-notification {
    description
      "Этот оператор применим только к уведомлениям и указывает, что
       это уведомление о смене состояния подписки и поэтому оно не
       передаётся в обычном потоке событий и для его получения не нужна
       специальная подписка. Оператор может применяться лишь как 
       субоператор оператора YANG notification и не предназначен для
       применения за пределами этого модуля YANG.";
  }

  /*
   * Идентификаторы
   */
  /* Ошибки RPC и уведомлений */

  identity delete-subscription-error {
    description
      "Базовый идентификатор для проблем, обнаруженных при попытке
       выполнить запрос RPC delete-subscription или kill-subscription.";
  }

  identity establish-subscription-error {
    description
      "Базовый идентификатор для проблем, обнаруженных при попытке
       выполнить запрос RPC establish-subscription.";
  }

  identity modify-subscription-error {
    description
      "Базовый идентификатор для проблем, обнаруженных при попытке
       выполнить запрос RPC modify-subscription.";
  }

  identity subscription-suspended-reason {
    description
      "Базовый идентификатор для проблем, сообщённых получателю как
       часть уведомления subscription-suspended.";
  }

  identity subscription-terminated-reason {
    description
      "Базовый идентификатор для проблем, сообщённых получателю как
       часть уведомления subscription-terminated.";
  }

  identity dscp-unavailable {
    base establish-subscription-error;
    if-feature "dscp";
    description
      "Издатель не способен промаркировать приоритет уведомлений так,
       чтобы это не менялось при передаче через сеть.";
  }

  identity encoding-unsupported {
    base establish-subscription-error;
    description
      "Невозможно представить уведомления в желаемом формате.";
  }

  identity filter-unavailable {
    base subscription-terminated-reason;
    description
      "Указанного фильтра нет, т. е. получатель указал фильтр,
       которого не существует или он не имеет к фильтру прав доступа.";
  }

  identity filter-unsupported {
    base establish-subscription-error;
    base modify-subscription-error;
    description
      "Невозможно разобрать фильтр. Причиной может быть синтаксическая
       ошибка или излишняя сложность фильтра для издателя.";
  }

  identity insufficient-resources {
    base establish-subscription-error;
    base modify-subscription-error;
    base subscription-suspended-reason;
    description
      "У издателя недостаточно ресурсов для поддержки запрошенной
       подписки. Например, выделенный CPU слишком ограничен для
       генерации нужного набора уведомлений.";
  }

  identity no-such-subscription {
    base modify-subscription-error;
    base delete-subscription-error;
    base subscription-terminated-reason;
    description
      "Указанной подписки нет. Это может быть связано с ошибочным
       идентификатором подписки, её принадлежностью другому подписчику
       или с указанием настраиваемой подписки.";
  }

  identity replay-unsupported {
    base establish-subscription-error;
    if-feature "replay";
    description
      "Невозможно выполнить воспроизведение для этой подписки, т. е.
       издатель не может предоставить запрошенные исторические сведения
       для потока событий этому получателю.";
  }

  identity stream-unavailable {
    base subscription-terminated-reason;
    description
      "Недоступный для подписки данным получателем поток событий.";
  }

  identity suspension-timeout {
    base subscription-terminated-reason;
    description
      "Прерывание приостановленной подписки. Издатель отменил подписку,
       время приостановки которой достигло предела.";
  }

  identity unsupportable-volume {
    base subscription-suspended-reason;
    description
      "У издателя нет достаточной пропускной способности сети для 
       передачи сгенерированных сведения, предназначенных получателю.";
  }

  /* Идентификаторы кодирования */

  identity configurable-encoding {
    description
      "Если транспортный идентификатор выведен из этого отождествления,
       это означает поддержку настройки кодирования. Примером 
       настраиваемого кодирования может служить новый идентификатор, 
       такой как encode-cbor. Такое отождествление может применять 
       configurable-encoding в качестве своей базы. Это позволяет
       динамической подписке, кодированной в JSON (RFC 8259), запросить
       кодирование уведомлений в (CBOR) (RFC 7049). Дополнительные
       детали в части настраиваемого кодирования можно найти в
       транспортном документе, основанном на этой спецификации.";
    reference
      "RFC 8259: The JavaScript Object Notation (JSON) Data
                 Interchange Format
       RFC 7049: Concise Binary Object Representation (CBOR)";
  }

  identity encoding {
    description
      "Базовый идентификатор для представления кодировки данных.";
  }

  identity encode-xml {
    base encoding;
    if-feature "encode-xml";
    description
      "Кодирование данных в XML, как описано в RFC 7950.";
    reference
      "RFC 7950: The YANG 1.1 Data Modeling Language";
  }

  identity encode-json {
    base encoding;
    if-feature "encode-json";
    description
      "Кодирование данных в JSON, как описано в RFC 7951.";
    reference
      "RFC 7951: JSON Encoding of Data Modeled with YANG";
  }

  /* Идентификатор для транспорта */

  identity transport {
    description
      "Идентификатор для базового механизма передачи уведомлений.";
  }

  /*
   * Определения типов
   */

  typedef encoding {
    type identityref {
      base encoding;
    }
    description
      "Задаёт кодированием данных, например, для подписки.";
  }

  typedef stream-filter-ref {
    type leafref {
      path "/sn:filters/sn:stream-filter/sn:name";
    }
    description
      "Этот тип служит для ссылки на фильтр потока событий.";
  }

  typedef stream-ref {
    type leafref {
      path "/sn:streams/sn:stream/sn:name";
    }
    description
      "Указывает предоставляемый системой поток событий.";
  }

  typedef subscription-id {
    type uint32;
    description
      "Тип для идентификаторов подписки.";
  }

  typedef transport {
    type identityref {
      base transport;
    }
    description
      "Задаёт транспорт для передачи уведомлений получателю.";
  }

  /*
   * Группировки
   */
  grouping stream-filter-elements {
    description
      "Задаёт базу для фильтров, применяемых к потокам событий.";
    choice filter-spec {
      description
        "Спецификация фильтра для этого запроса.";
      anydata stream-subtree-filter {
        if-feature "subtree";
        description
          "Критерии оценки потока событий в форме фильтра по ветвям,
           определённого в разделе 6 RFC 6241.

           Фильтр ветвей применяется к представлению отдельных 
           выделенных записей в потоке событий.

           Если фильтр возвращает непустой набор узлов, записи событий
           включаются в уведомление, отправляемое получателям.";
        reference
          "RFC 6241: Network Configuration Protocol (NETCONF),
                     Section 6";
      }
      leaf stream-xpath-filter {
        if-feature "xpath";
        type yang:xpath1.0;
        description
          "Критерии оценки потока событий в форме выражения XPath 1.0.

           Выражение XPath оценивается для представления отдельных 
           выделенных записей в потоке событий.

           Результат выражения XPath преобразуется в логическое значение
           с использованием стандартных правил XPath 1.0. Значение true
           указывает включение записи в уведомление, передаваемое
           получателям.

           Выражения оцениваются в описанном ниже контексте XPath.
             - Набор объявлений пространств имён - это набор пар 
               «префикс, пространство имен» для всех модулей YANG,
               реализованных сервером, где префиксом служит имя модуля
               YANG, а пространство имён задаёт оператор namespace в
               модуле YANG.
               Если лист кодируется в XML, все объявления пространств
               имён в области действия листа stream-xpath-filter
               добавляются к набору объявлений пространств имён. Если 
               префикс, найденный в XML, уже есть в наборе объявлений, 
               применяется пространство имён в XML.
             - Набор привязок переменных пуст.
             - Библиотека функций состоит из ядра библиотеки функций и
               функций XPath из раздела 10 в RFC 7950.
             - Узлом контекста служит корневой узел хранилища.";
        reference
          "XML Path Language (XPath) Version 1.0
           (https://www.w3.org/TR/1999/REC-xpath-19991116) 
           RFC 7950: The YANG 1.1 Data Modeling Language,
                     Section 10";
      }
    }
  }

  grouping update-qos {
    description
      "Описывает сведения QoS для подписки, передаваемые нижележащему
       транспорту для приоритизации и обработки.";
    leaf dscp {
      if-feature "dscp";
      type inet:dscp;
      default "0";
      description
        "Желаемый уровень транспортного приоритета для уведомлений,
         инкапсулирующих содержимое подписки. Этот приоритет 
         применяется для всех получателей данной подписки.";
    }
    leaf weighting {
      if-feature "qos";
      type uint8 {
        range "0 .. 255";
      }
      description
        "Относительный вес для подписки. Большее значение соответствует
         большим ресурсам. Это позволяет базовому транспорту обоснованно
         распределять ресурсы между подписками.";
      reference
        "RFC 7540: Hypertext Transfer Protocol Version 2 (HTTP/2),
                   Section 5.3.2";
    }
    leaf dependency {
      if-feature "qos";
      type subscription-id;
      description
        "Указывает subscription-id родительской подписки, которая имеет
         абсолютный приоритет при наличии у неё push-обновлений, готовых
         к передаче от издателя. Иными словами, при наличии у родителя
         данных для передачи никакие потоковые объекты текущей подписки
         не следует передавать.

         Если зависимость задана в конфигурации или вызовом RPC, но
         указанного subscription-id нет, зависимость игнорируется. Если
         указанная подписка удалена, зависимость тоже удаляется.";
      reference
        "RFC 7540: Hypertext Transfer Protocol Version 2 (HTTP/2),
                   Section 5.3.1";
    }
  }

  grouping subscription-policy-modifiable {
    description
      "Описывает все объекты подписки, которые могут меняться.";
    choice target {
      mandatory true;
      description
        "Указывает источник сведений для подписки, а также желаемый
         набор информации из этого источника.";
      case stream {
        choice stream-filter {
          description
            "Фильтр событий для подписки, указываемый ссылкой на 
             глобальный список фильтров или явно заданный в подписке.";
          case by-reference {
            description
              "Применять фильт, настраиваемый отдельно.";
            leaf stream-filter-name {
              type stream-filter-ref;
              mandatory true;
              description
                "Ссылка на имеющийся фильтр потока событий, для 
                 применения к подписке.";
            }
          }
          case within-subscription {
            description
              "Локальное определение позволяет фильтру событий иметь
               такой же жизненный цикл, как у подписки.";
            uses stream-filter-elements;
          }
        }
      }
    }
    leaf stop-time {
      type yang:date-and-time;
      description
        "Указывает время, когда передачу уведомлений для подписки
         следует прекратить. Если время stop-time не задано, уведомления
         будут передаваться до прерывания подписки. При наличии
         replay-start-time значение stop-time должно быть больше. Если
         replay-start-time не задано, stop-time при организации подписки
         должно указывать будущее время.";
    }
  }

  grouping subscription-policy-dynamic {
    description
      "Описывает информацию о подписке, которая может быть передана
       только через вызовы RPC, заданные в этой модели данных.";
    uses subscription-policy-modifiable {
      augment "target/stream" {
        description
          "Добавляет объекты, которые можно изменить этим вызовом RPC.";
        leaf stream {
          type stream-ref {
            require-instance false;
          }
          mandatory true;
          description
            "Указывает поток событий, рассматриваемый для подписки.";
        }
        leaf replay-start-time {
          if-feature "replay";
          type yang:date-and-time;
          config false;
          description
            "Служит для включения функции replay в динамической 
             подписке для записей о событиях, произошедших не ранее
             указанного времени. Если replay-start-time не указано,
             это не будет подписка на воспроизведение и выталкивание
             событий следует начинать сразу. Недопустимо указывать 
             текущее или будущее время.";
        }
      }
    }
    uses update-qos;
  }

  grouping subscription-policy {
    description
      "Описывает полный набор правил для динамических и настраиваемых
       подписок, за исключением получателей и сетевых сведений,
       специфических для издателя, таких как интерфейс, который следует
       использовать для передачи уведомлений.";
    uses subscription-policy-dynamic;
    leaf transport {
      if-feature "configured";
      type transport;
      description
        "Для настраиваемой подписки задаёт транспорт, применяемый при
         доставке сообщений получателям этой подписки.";
    }
    leaf encoding {
      when 'not(../transport) or derived-from(../transport,
      "sn:configurable-encoding")';
      type encoding;
      description
        "Тип кодирования уведомлений. Для динамической подписки без 
         указания кодирования в RPC establish-subscription будет
         применяться кодирование, использованное в RPC. Если для 
         настраиваемой подписки значение не задано явно, применяется
         заданное по умолчанию кодирование базового транспорта.";
    }
    leaf purpose {
      if-feature "configured";
      type string;
      description
        "Текст, позволяющий настраивающему объекту задать источник и
         другую специфику данной подписки.";
    }
  }

  /*
   * RPC
   */

  rpc establish-subscription {
    description
      "Этот вызов RPC позволяет подписчику организовать (возможно, и
       согласовать) подписку от своего имени. При успешном выполнении
       подписка будет действовать на протяжении всей ассоциации
       подписчика с издателем или до прерывания подписки. Если возникает
       ошибка или издатель не может выполнить требования подписки,
       возвращается ошибка RPC и подписка не организуется. В этом случае
       error-info в отклике RPC МОЖЕТ включать параметры, применение
       которых повысит вероятность успеха следующего запроса
       establish-subscription.";
    input {
      uses subscription-policy-dynamic;
      leaf encoding {
        type encoding;
        description
          "Тип кодирования для данных подписки. Если типе не указан при
           вызове RPC, издатель ДОЛЖЕН применять кодирование, 
           использованное для RPC.";
      }
    }
    output {
      leaf id {
        type subscription-id;
        mandatory true;
        description
          "Идентификатор, используемый для этой подпсики.";
      }
      leaf replay-start-time-revision {
        if-feature "replay";
        type yang:date-and-time;
        description
          "При запросе воспроизведения представляет начальный момент
           воспроизведения из буфера запрошенного потока событий. 
           Значение этого листа совпадает с replay-log-aged-time при
           его наличии, иначе совпадает с replay-log-creation-time. 
           Получателю воспроизводятся все записи после этого времени.
           Этот лист передаётся лишь в том случае, когда указанное 
           время начала позже запрошенного подписчиком времени.";
      }
    }
  }

  rc:yang-data establish-subscription-stream-error-info {
    container establish-subscription-stream-error-info {
      description
        "Если любой из параметров RPC establish-subscription не подходит
         для этого потока событий, подписка не организуется и отклик об
         ошибке RPC ДОЛЖЕН указывать причину отказа. Этот элемент
         yang-data МОЖЕТ включаться как структурированные данные отклика
         об ошибке RPC для указания причины отказа. Элемент yang-data
         ДОЛЖЕН включаться, если подписчику возвращаются подсказки.";
      leaf reason {
        type identityref {
          base establish-subscription-error;
        }
        description
          "Указывает причину отказа в подписке на этот поток событий.";
      }
      leaf filter-failure-hint {
        type string;
        description
          "Сведения о причине отказа в подписке. Синтаксис и семантика 
           подсказки зависят от реализации.";
      }
    }
  }

  rpc modify-subscription {
    description
      "Этот вызов RPC позволяет подписчику изменить параметры 
       динамической подписки. При успешном изменении новые параметры
       сохраняются до завершения подписки или новой смены параметров.
       В случае ошибки или невозможности установить запрошенные 
       параметры подписка не изменяется и сохраняются исходные
       параметры. В этом случае отклик об ошибке RPC МОЖЕТ включать в
       error-info параметры, которые повысят вероятность успеха при
       последующем вызове modify-subscription. Успешное выполнение
       modify-subscription переводит приостановленную подписку в
       состояние active.";
    input {
      leaf id {
        type subscription-id;
        mandatory true;
        description
          "Идентификатор для использования с этой подпиской.";
      }
      uses subscription-policy-modifiable;
    }
  }

  rc:yang-data modify-subscription-stream-error-info {
    container modify-subscription-stream-error-info {
      description
        "Этот элемент yang-data МОЖЕТ возвращаться как часть отклика об
         ошибке RPC modify-subscription для потока событий. Этот элемент
         ДОЛЖЕН использоваться при возврате советов подписчику.";
      leaf reason {
        type identityref {
          base modify-subscription-error;
        }
        description
          "Сведения в отклике об ошибке RPC modify-subscription, 
           указывающие причину отказа от изменения подписки.";
      }
      leaf filter-failure-hint {
        type string;
        description
          "Сведения о неприемлемости фильтра для подписки. Синтаксис
           и семантика подсказки зависят от реализации.";
      }
    }
  }

  rpc delete-subscription {
    description
      "Этот вызов RPC позволяет подписчику удалить созданную им подписку
       с помощью RPC establish-subscription. При возникновении ошибки
       сервер возвращает отклик rpc-error, где поле error-info МОЖЕТ
       содержать структуру delete-subscription-error-info.";
    input {
      leaf id {
        type subscription-id;
        mandatory true;
        description
          "Идентификатор удаляемой подписки. С помощью этого вызова RPC
           можно удалить лишь подписку, созданную вызовом RPC
           establish-subscription из того же источника.";
      }
    }
  }

  rpc kill-subscription {
    nacm:default-deny-all;
    description
      "Этот вызов RPC позволяет оператору удалить динамическую подписку, 
       независимо от исходного подписчика и базовой транспортной сессии.
       При возникновении ошибки сервер возвращает отклик rpc-error, где
       поле error-info МОЖЕТ содержать delete-subscription-error-info.";
    input {
      leaf id {
        type subscription-id;
        mandatory true;
        description
          "Идентификатор удаляемой подписки. С помощью этого вызова RPC
           можно удалить лишь подписки, организованные 
           с помощью establish-subscription.";
      }
    }
  }

  rc:yang-data delete-subscription-error-info {
    container delete-subscription-error-info {
      description
        "При отказе RPC delete-subscription или kill-subscription 
         подписка не удаляется и отклик об ошибке RPC ДОЛЖЕН указывать
         причину этого отказа. Эта структура yang-data МОЖЕТ включаться 
         отклик об ошибке RPC для указания причины отказа.";
      leaf reason {
        type identityref {
          base delete-subscription-error;
        }
        mandatory true;
        description
          "Указывает причину отказа при удалении подписки.";
      }
    }
  }

  /*
   * Уведомления
   */

  notification replay-completed {
    sn:subscription-state-notification;
    if-feature "replay";
    description
      "Уведомление, указывающее, что все воспроизводимые уведомления
       были переданы.";
    leaf id {
      type subscription-id;
      mandatory true;
      description
        "Указывает подписку для воздействия.";
    }
  }

  notification subscription-completed {
    sn:subscription-state-notification;
    if-feature "configured";
    description
      "Указывает, что для подписки завершена передача записей о событиях
       по значению stop-time.";

    leaf id {
      type subscription-id;
      mandatory true;
      description
        "Указывает аккуратно завершённую подписку.";
    }
  }

  notification subscription-modified {
    sn:subscription-state-notification;
    description
      "Указывает, что подписка была изменена. Передаваемые после этого
       уведомления будут соответствовать новым условиям подписки. Для
       полноты это уведомление о смене статуса подписки включает
       исходные и изменённые параметры подписки.";
    leaf id {
      type subscription-id;
      mandatory true;
      description
        "Указывает подписку для воздействия.";
    }
    uses subscription-policy {
      refine "target/stream/stream-filter/within-subscription" {
        description
          "Фильтр для подписки. Если задан лист stream-filter-name, 
           фильтр для подписки берётся из контейнера filters, иначе
           он задаётся явно как часть подписки.";
      }
    }
  }

  notification subscription-resumed {
    sn:subscription-state-notification;
    description
      "Указывает, что ранее приостановленная подписка возобновлена и
       уведомления снова будут передаваться. Кроме того, 
       subscription-resumed указывает, что параметры подписки не
       изменились с момента передачи последней записи о событии.";
    leaf id {
      type subscription-id;
      mandatory true;
      description
        "Указывает подписку для воздействия.";
    }
  }

  notification subscription-started {
    sn:subscription-state-notification;
    if-feature "configured";
    description
      "Указывает, что подписка активирована и уведомления будут
       передаваться.";
    leaf id {
      type subscription-id;
      mandatory true;
      description
        "Указывает подписку для воздействия.";
    }
    uses subscription-policy {
      refine "target/stream/replay-start-time" {
        description
          "Указывает время, используемые для воспроизведения потока
           записанных событий. Значение совпадает с большим (поздним) из
           времени события в предыдущей записи, переданной получателю, 
           replay-log-creation-time, replay-log-aged-time или 
           последней загрузки издателя.";
      }
      refine "target/stream/stream-filter/within-subscription" {
        description
          "Фильтр, применяемый к подписке. Если задано значение
           stream-filter-name, фильтр подписки берётся из контейнера
           filters, иначе указывается явно как часть подписки.";
      }
      augment "target/stream" {
        description
          "Добавляет параметры, связанные с уведомлением 
           subscription-started.";
        leaf replay-previous-event-time {
          when '../replay-start-time';
          if-feature "replay";
          type yang:date-and-time;
          description
            "При наличии в буфере воспроизведения хотя бы одного события
             до replay-start-time этот лист указывает время события,
             сгенерированного непосредственно перед replay-start-time.

             Если получатель ранее принимал записи событий для этой
             настраиваемой подписки, он может сравнить это время с 
             ранее полученной записью о событии. При несовпадении 
             (возможно из-за перезагрузки), может быть инициировано
             динамическое воспроизведение отсутствующих записей.";
        }
      }
    }
  }

  notification subscription-suspended {
    sn:subscription-state-notification;
    description
      "Указывает приостановку подписки издателем. Уведомления не будут
       передаваться до возобновления подписки. Это уведомление нужно
       передавать только получателям подписки, оно не является
       уведомлением общего назначения.";
    leaf id {
      type subscription-id;
      mandatory true;
      description
        "Указывает подписку для воздействия.";
    }
    leaf reason {
      type identityref {
        base subscription-suspended-reason;
      }
      mandatory true;
      description
        "Указывает условия, вызвавшие приостановку подписки.";
    }
  }

  notification subscription-terminated {
    sn:subscription-state-notification;
    description
      "Указывает прерывание подписки.";
    leaf id {
      type subscription-id;
      mandatory true;
      description
        "Указывает подписку для воздействия.";
    }
    leaf reason {
      type identityref {
        base subscription-terminated-reason;
      }
      mandatory true;
      description
        "Указывает условия, вызвавшие прерывание подписки.";
    }
  }

  /*
   * Узлы данных
   */
  container streams {
    config false;
    description
      "Сведения из встроенного потока событий от издателя.";
    list stream {
      key "name";
      description
        "Указывает встроенные потоки событий, поддерживаемые издателем";
      leaf name {
        type string;
        description
          "Дескриптор предоставляемого системой потока событий, 
           состоящего из набора последовательных записей, каждая из
           которых характеризуется своим доменом и семантикой.";
      }
      leaf description {
        type string;
        description
          "Описание потока событий, включающее такие сведения, как тип
           записей о событиях, доступных в этом потоке событий.";
      }
      leaf replay-support {
        if-feature "replay";
        type empty;
        description
          "Указывает, что в потоке событий есть запись для 
           воспроизведения.";
      }
      leaf replay-log-creation-time {
        when '../replay-support';
        if-feature "replay";
        type yang:date-and-time;
        mandatory true;
        description
          "Временная метка создания журнальной записи, применяемая для
           поддержки функции воспроизведения в данном потоке событий.
           Это время  может быть раньше наиболее ранней из доступных в
           журнале записей. Объект обновляется при сбросе журнала.";
      }
      leaf replay-log-aged-time {
        when '../replay-support';
        if-feature "replay";
        type yang:date-and-time;
        description
          "Временная метка последней записи о событии, удалённой из
           журнала. Метка указывает, как далеко распространяется журнал
           в прошлое, если журнал не достигает прошлого времени 
           replay-log-creation-time. Этот объект ДОЛЖЕН присутствовать,
           если поддерживается воспроизведение и какая-либо запись 
           удалена из журнала.";
      }
    }
  }
  container filters {
    description
      "Список настраиваемых фильтров, которые применимы к подписке. Это
       позволяет многократно применять заданные сложные фильтры.";
    list stream-filter {
      key "name";
      description
        "Список заданных фильтров, применимых к подпискам.";
      leaf name {
        type string;
        description
          "Имя для указания фильтра.";
      }
      uses stream-filter-elements;
    }
  }
  container subscriptions {
    description
      "Список активных в данный момент подписок, служащий для управления
       и мониторинга подписок. Это включает подписки, организованные
       через примитивы RPC и организованные путём настройки.";

    list subscription {
      key "id";
      description
        "Идентификатор и конкретные параметры подписки. Подписки из 
         этого списка могли быть созданы с использованием канала 
         управления, RPC или настройки конфигурации.

         Если для удаления подписки применяется RPC kill-subscription 
         или операции настройки, сообщение subscription-terminated
         передаётся всем активным и приостановленным получателям.";
      leaf id {
        type subscription-id;
        description
          "Идентификатор подписки, уникальный у издателя.";
      }
      uses subscription-policy {
        refine "target/stream/stream" {
          description
            "Указывает поток событий, рассматриваемый для этой подписки.
             Если поток событий удалён или не может быть указан активной
             подпиской, передаётся уведомление subscription-terminated с
             указанием причины stream-unavailable. Если настраиваемая
             подписка указывает отсутствующий поток событий, подписка
             переводится в состояние invalid.";
        }
        refine "transport" {
          description
            "Для настраиваемой подписки этот лист задаёт транспорт,
             применяемый для доставки сообщений, предназначенных всем
             получателям этой подписки. Этот объект обязателен для
             подписок в хранилище данных конфигурации. Объект
             (1) необязателен для динамических подписок в хранилище 
             данных рабочего состояния и его (2) не следует применять
             для других типов динамической подписки.";
        }
        augment "target/stream" {
          description
            "Позволяет добавлять объекты в настраиваемую подписку.";
          leaf configured-replay {
            if-feature "configured";
            if-feature "replay";
            type empty;
            description
              "Присутствие этого листа указывает, что воспроизведение
               для настраиваемой подписки следует начинать с указанного 
               момента в журнале событий или с момента загрузки издателя
               (что позднее).";
          }
        }
      }
      choice notification-message-origin {
        if-feature "configured";
        description
          "Указывает выходной интерфейс издателя для отправки 
           уведомлений.";
        case interface-originated {
          description
            "Уведомления предназначены для передачи через указанный
             интерфейс издателя.";
          leaf source-interface {
            if-feature "interface-designation";
            type if:interface-ref;
            description
              "Указывает интерфейс для передачи уведомлений.";
          }
        }
        case address-originated {
          description
            "Уведомления от издателя должны передаваться с конкретного
             адреса источника и/или контекста маршрутизации.";
          leaf source-vrf {
            if-feature "supports-vrf";
            type leafref {
              path "/ni:network-instances/ni:network-instance/ni:name";
            }
            description
              "VRF для отправки уведомлений от издателя.";
          }
          leaf source-address {
            type inet:ip-address-no-zone;
            description
              "Адрес источника в уведомлениях. Если VRF существует, но
               этого объекта нет, ДОЛЖЕН применяться заданный по умолчанию 
               адрес издателя для этого экземпляра VRF.";
          }
        }
      }

      leaf configured-subscription-state {
        if-feature "configured";
        type enumeration {
          enum valid {
            value 1;
            description
              "Эта подписка поддерживается с её текущими параметрами.";
          }
          enum invalid {
            value 2;
            description
              "Эта подписка не поддерживается с текущими параметрами.";
          }
          enum concluded {
            value 3;
            description
              "Подписка неактивна, поскольку наступило время остановки.
               Больше нет подписчиков со статусом active или suspended, 
               но подписка ещё не удалена из конфигурации.";
          }
        }
        config false;
        description
          "Наличие этого листа указывает, что подписка организована 
           настройкой, а не через канал управления или RPC. Значение
           указывает статус подписки, установленный издателем.";
      }
      container receivers {
        description
          "Набор получателей для подписки.";
        list receiver {
          key "name";
          min-elements 1;
          description
            "Хост, считающийся получателем уведомлений в подписке. Для
             настраиваемой подписки транспортные параметры (или
             leafref для этих параметров) могут быть дополнены 
             конкретным получателем п этом списке.";
          leaf name {
            type string;
            description
              "Указывает уникального получателя для подписки.";
          }

          leaf sent-event-records {
            type yang:zero-based-counter64;
            config false;
            description
              "Число записей о событиях, переданных получателю. Счётчик 
               инициализируется при организации динамической подписки 
               или переходе настроенного получателя в состояние valid.";
          }
          leaf excluded-event-records {
            type yang:zero-based-counter64;
            config false;
            description
              "Число записей о событиях, явно удалённых фильтром событий
               потока или контролем доступа, чтобы они не были переданы
               получателю. Счётчик сбрасывается в 0 при каждой 
               инициализации sent-event-records.";
          }
          leaf state {
            type enumeration {
              enum active {
                value 1;
                description
                  "Указывает получателя всех подходящих сообщений для
                   подписки.";
              }
              enum suspended {
                value 2;
                description
                  "Получателю установлен статус suspended, поскольку
                   издатель в данное время не может предоставить 
                   сообщения для подписки.";
              }
              enum connecting {
                value 3;
                if-feature "configured";
                description
                  "Подписка настроена, но перед отправкой уведомлений
                   нужно получить уведомление subscription-started о
                   смене состояния подписки.

                   Если было вызвано действие reset для получателя
                   активной настраиваемой подписки, состояние должно 
                   быть изменено на connecting.";
              }

              enum disconnected {
                value 4;
                if-feature "configured";
                description
                  "Отказ при отправке получателю уведомления
                   subscription-started. Дополнительные попытки 
                   соединения в настоящее время не предпринимаются.";
              }
            }
            config false;
            mandatory true;
            description
              "Состояние подписки с точки зрения конкретного получателя.
               С помощью этих сведений можно определить, генерирует ли 
               издатель уведомления для этого получателя.";
          }
          action reset {
            if-feature "configured";
            description
              "Позволяет сбросить состояние для получателя настраиваемой
               подписки в connecting. Это даёт возможность заново 
               инициализировать соединение.";
            output {
              leaf time {
                type yang:date-and-time;
                mandatory true;
                description
                  "Время, когда издатель вернул для получателя состояние
                   connecting.";
              }
            }
          }
        }
      }
    }
  }
}
<CODE ENDS>

5. Взаимодействие с IANA

Агентство IANA зарегистрировало URI в субреестре ns реестра IETF XML Registry [RFC3688], доступном по ссылке <https://www.iana.org/assignments/xml-registry>, в соответствии с [RFC3688]

   URI: urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications
   Registrant Contact: The NETCONF WG of the IETF.
   XML: N/A; запрошенный URI является пространством имён XML.

Агентство IANA зарегистрировало модуль YANG в реестре YANG Module Names [RFC6020], доступном по ссылке <https://www.iana.org/assignments/yang-parameters>, в соответствии с [RFC6020]

   Name: ietf-subscribed-notifications
   Namespace: urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications
   Prefix: sn
   Reference: RFC 8639

6. Вопросы реализации

Для поддержки реализаций со статическими и настраиваемыми подписками рекомендуется разделить домен идентификаторов подписки на статическую и динамическую часть. Это предотвратит конфликты, связанные с указанием для настраиваемой подписки значения subscription-id, уже выделенного динамически. Разумным решением является использование нижней половины пространства целочисленных идентификаторов для выделения внешними объектами (настраиваемая подписка). Верхняя половина пространства идентификаторов динамически распределяется издателем.

Если подписка не способна поместить серию отфильтрованных записей о событиях в пригодные для передачи сообщения, отправку для получателя следует приостановить с указанием причины unsupportable-volume.

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

Для настраиваемых подписок с воспроизведением получатели защищаются от дубликатов событий, вытолкнутых после перезагрузки издателя. Однако получатель может захотеть видеть записи о событиях, которые не удалось доставить непосредственно перед перезагрузкой. Доставка таких записей возможна путём указания <eventTime> [RFC5277] из последней записи о событии, полученной до уведомления subscription-started о смене состояния подписки. С помощью этого <eventTime> и replay-start-time из уведомления subscription-started можно организовать независимую динамическую подписку, где будут переданы записи, которые были созданы, но не отправлены получателю.

7. Транспортные требования

В этом разделе приведены требования к транспортировке уведомлений по подписке в поддержку описанного решения.

Транспорт, выбранный подписчиком для доступа к издателю, должен поддерживать множество запросов establish-subscription в одной транспортной сессии.

Для настраиваемой и динамической подписки издатель должен проверять подлинность получателя с помощью того или иного механизма транспортного уровня до начала отправки каких-либо записей о событиях. Кроме того, получатель должен аутентифицировать издателя на транспортном уровне. Результатом является взаимная проверка подлинности.

Настоятельно рекомендуется защищённый транспорт. Помимо этого издатель должен проверить наличие у получателя достаточных прав для выполнения запрашиваемой функции применительно к вовлечённому содержимому.

Спецификация транспорта на основе этого докуме6нта может (но не обязана) требовать использования одного логического канала для RPC и записей о событиях. Однако записи событий и уведомления о смене статуса подписки должны передаваться в одной транспортной сессии для соблюдения порядка доставки.

Спецификация транспорта должна указывать поддерживаемое кодирование. Если транспорт настраиваемой подписки поддерживает разное кодирование, спецификация должна задавать принятый по умолчанию вариант.

Если подписчик включает лист dscp в запрос establish-subscription, он должен понимать и учитывать, как соответствующий код DSCP будет представлен в домене издателя.

Дополнительные требования будут зависеть от выбора транспорта для подписки. Пример требований приведён в [RFC8640].

8. Вопросы безопасности

Описанный в этом документе модуль YANG определяет схему данных, которая предназначения для доступа по протоколам сетевого управления, таким как NETCONF [RFC6241] или RESTCONF [RFC8040]. Нижним уровнем NETCONF является защищённый транспорт с обязательной поддержкой SSH4 [RFC6242]. Нижним уровнем RESTCONF является HTTPS с обязательной поддержкой TLS [RFC5246].

Модель управления доступом NETCONF (Network Configuration Access Control Model или NACM) [RFC8341] обеспечивает способы ограничения доступа отдельным пользователям NETCONF или RESTCONF заданным подмножеством всех доступных операций и содержимого NETCONF или RESTCONF.

При настраиваемой подписке можно использовать один или несколько издателей для перегрузки получателя. Чтобы предотвратить это, не следует передавать уведомления получателям, не поддерживающим эту спецификацию. Получателю, не желающему видеть уведомления, нужно лишь прервать или отвергнуть транспортные сессии с издателем.

Когда получатель видит новое сообщение subscription-started для подписки, где он уже принимает уведомления, это может говорить о том, что злоумышленник выполнил какие-то действия, которые нарушили связность получателя. Для извлечения событий, потерянных в течение интервала отсутствия связности получателю следует извлечь записи, созданные с момента последнего полученного события. Это можно сделать с помощью динамической подписки на воспроизведение с теми же фильтрами (в предположении поддержки издателем функции replay).

Для динамических подписок требуется защита реализаций от злонамеренных и ошибочных подписчиков, которые могут передавать большое число запросов establish-subscription, потребляя ресурсы системы. Операторам следует выполнять мониторинг таких случаев и при обнаружении предпринимать действия по ограничению потребляемых ресурсов, например, приостанавливая или прерывая часть подписок или прерывая транспортные сессии, если применяется сеансовый транспорт.

Механизмы воспроизведения, описанные в параграфах 2.4.2.1 и 2.5.6, предоставляют доступ к истории записей о событиях. Модель управления доступом, защищающая эти записи, по своему устройству может разрешить доступ пользователям, которые не имели полномочий на момент сбора сведений.

Использование DNS для поиска имён настраиваемых пользователей может приводить к ситуациям, когда имя распознаётся не так, как ожидает издатель и получатель будет отличаться от предполагаемого.

Злоумышленник, способный заставить издателя использовать некорректное время, может вызвать воспроизведение сообщений путём установки времени в прошлом и создать риск потери сообщений, передвинув время в будущее.

Многие узлы данных в описанном здесь модуле YANG позволяют доступ для записи, создания, удаления (writable/creatable/deletable, т. е. config true, как установлено по умолчанию). Такие узлы могут содержать конфиденциальные сведения или быть уязвимыми в некоторых сетевых средах. Операции записи (например, edit-config) для таких узлов без подобающей защиты могут отрицательно влиять на работу сети. Ниже перечислены ветви и узлы данных с указанием возможных уязвимостей.

Контейнер /filters

stream-subtree-filter, stream-xpath-filter

Обновление фильтра может повысить сложность расчётов для всех применяющих фильтр подписчиков.

Контенер /subscriptions

Ниже приведены соображения, относящиеся только к операциям настройки конфигурации настраиваемых подписок.

configured-replay

Может использоваться для передачи подписчику большого числа записей о событиях.

dependency

Может использоваться для принудительного размещения важных событий в очереди после малозначимых.

dscp

Некорректная маркировка может привести к передаче трафика с приоритетом выше гарантированного.

id

Может переопределить имеющуюся подписку, возможно настроенную другим объектом.

name

Добавление ключевой записи может использоваться для попытки передать трафик нежелательному получателю.

replay-start-time

Может использоваться для выталкивания большого числа записей журнала, что ведёт к истощению ресурсов.

source-address

Заданный адрес может не позволить передачу трафика нужному получателю.

source-interface

Заданный интерфейс может не позволить передачу трафика нужному получателю.

source-vrf

Может разместить подписку в виртуальной сети, где получатели не имеют права просматривать её содержимое.

stop-time

Может использоваться для прерывания содержимого в неподходящий момент.

stream

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

stream-filter-name

Можно установить фильтр, не соответствующий потоку событий.

stream-subtree-filter

Сложный фильтр может потребовать больших вычислительных ресурсов для данной подписки.

stream-xpath-filter

Сложный фильтр может потребовать больших вычислительных ресурсов для данной подписки.

weighting

Указание большого веса может перегрузить очереди других подписчиков.

Некоторые из доступных для чтения узлов модуля YANG могут считаться конфиденциальными или уязвимыми в отдельных сетевых средах. Для таких узлов важно контролировать операции чтения (например, get, get-config, notification). Ниже перечислены субдеревья и узлы данных с указанием возможных уязвимостей.

Контейнер /streams

name

Если контроль доступа не настроен должным образом, могут раскрываться внутренние сведения системы.

replay-support

Если контроль доступа не настроен должным образом, могут раскрываться журнальные записи.

Контейнер /subscriptions

excluded-event-records

Этот лист может давать сведения о фильтруемых записях событий. Оператору сети следует иметь полномочия для доступа к таким сведениям. Раскрытие получателю сведений о числе отфильтрованных событий может приводить к утечке информации о наличии фильтров, которые могут применяться для этого получателя.

subscription

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

Некоторые из операций RPC в этом модуле YANG могут быть чувствительны или уязвимы в той или иной сетевой среде. Важно контролировать доступ к таким операциям. Ниже указаны такие операции.

Все RPC

Если ошибочный или враждебный подписчик передаёт неожиданно большое число RPC, это может приводить к избыточному расходу системных ресурсов издателя просто для определения приемлемости подписки. В таких случаях взаимодействие с подписчиками может прерываться путём разрыва транспортных сессий.

RPC delete-subscription

Нет особых соображений.

RPC establish-subscription, modify-subscription

Подписчики могут перегрузить ресурсы издателя, поэтому издатель должен гарантировать наличие ресурсов для выполнения запроса, а при недостатке ресурсов должен отвергать запрос.

RPC kill-subscription

Вызов RPC kill-subscription должен быть защищён, чтобы только соединения с административными правами могли применять этот вызов RPC.

9. Литература

9.1. Нормативные документы

[RFC2119] Bradner, S., «Key words for use in RFCs to Indicate Requirement Levels», BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, <https://www.rfc-editor.org/info/rfc2119>.

[RFC2474] Nichols, K., Blake, S., Baker, F., and D. Black, «Definition of the Differentiated Services Field (DS Field) in the IPv4 and IPv6 Headers», RFC 2474, DOI 10.17487/RFC2474, December 1998, <https://www.rfc-editor.org/info/rfc2474>.

[RFC3688] Mealling, M., «The IETF XML Registry», BCP 81, RFC 3688, DOI 10.17487/RFC3688, January 2004, <https://www.rfc-editor.org/info/rfc3688>.

[RFC5246] Dierks, T. and E. Rescorla, «The Transport Layer Security (TLS) Protocol Version 1.2», RFC 5246, DOI 10.17487/RFC5246, August 2008, <https://www.rfc-editor.org/info/rfc5246>.

[RFC5277] Chisholm, S. and H. Trevino, «NETCONF Event Notifications», RFC 5277, DOI 10.17487/RFC5277, July 2008, <https://www.rfc-editor.org/info/rfc5277>.

[RFC6020] Bjorklund, M., Ed., «YANG — A Data Modeling Language for the Network Configuration Protocol (NETCONF)», RFC 6020, DOI 10.17487/RFC6020, October 2010, <https://www.rfc-editor.org/info/rfc6020>.

[RFC6241] Enns, R., Ed., Bjorklund, M., Ed., Schoenwaelder, J., Ed., and A. Bierman, Ed., «Network Configuration Protocol (NETCONF)», RFC 6241, DOI 10.17487/RFC6241, June 2011, <https://www.rfc-editor.org/info/rfc6241>.

[RFC6242] Wasserman, M., «Using the NETCONF Protocol over Secure Shell (SSH)», RFC 6242, DOI 10.17487/RFC6242, June 2011, <https://www.rfc-editor.org/info/rfc6242>.

[RFC6991] Schoenwaelder, J., Ed., «Common YANG Data Types», RFC 6991, DOI 10.17487/RFC6991, July 2013, <https://www.rfc-editor.org/info/rfc6991>.

[RFC7950] Bjorklund, M., Ed., «The YANG 1.1 Data Modeling Language», RFC 7950, DOI 10.17487/RFC7950, August 2016, <https://www.rfc-editor.org/info/rfc7950>.

[RFC7951] Lhotka, L., «JSON Encoding of Data Modeled with YANG», RFC 7951, DOI 10.17487/RFC7951, August 2016, <https://www.rfc-editor.org/info/rfc7951>.

[RFC8040] Bierman, A., Bjorklund, M., and K. Watsen, «RESTCONF Protocol», RFC 8040, DOI 10.17487/RFC8040, January 2017, <https://www.rfc-editor.org/info/rfc8040>.

[RFC8174] Leiba, B., «Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words», BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017, <https://www.rfc-editor.org/info/rfc8174>.

[RFC8341] Bierman, A. and M. Bjorklund, «Network Configuration Access Control Model», STD 91, RFC 8341, DOI 10.17487/RFC8341, March 2018, <https://www.rfc-editor.org/info/rfc8341>.

[RFC8342] Bjorklund, M., Schoenwaelder, J., Shafer, P., Watsen, K., and R. Wilton, «Network Management Datastore Architecture (NMDA)», RFC 8342, DOI 10.17487/RFC8342, March 2018, <https://www.rfc-editor.org/info/rfc8342>.

[RFC8343] Bjorklund, M., «A YANG Data Model for Interface Management», RFC 8343, DOI 10.17487/RFC8343, March 2018, <https://www.rfc-editor.org/info/rfc8343>.

[RFC8529] Berger, L., Hopps, C., Lindem, A., Bogdanovic, D., and X. Liu, «YANG Data Model for Network Instances», RFC 8529, DOI 10.17487/RFC8529, March 2019, <https://www.rfc-editor.org/info/rfc8529>.

[W3C.REC-xml-20081126] Bray, T., Paoli, J., Sperberg-McQueen, M., Maler, E., and F. Yergeau, «Extensible Markup Language (XML) 1.0 (Fifth Edition)», World Wide Web Consortium Recommendation REC-xml-20081126, November 2008, <https://www.w3.org/TR/2008/REC-xml-20081126>.

[XPATH] Clark, J. and S. DeRose, «XML Path Language (XPath) Version 1.0», November 1999, <https://www.w3.org/TR/1999/REC-xpath-19991116>.

9.2. Дополнительная литература

[RESTCONF-Notif] Voit, E., Rahman, R., Nilsen-Nygaard, E., Clemm, A., and A. Bierman, «Dynamic subscription to YANG Events and Datastores over RESTCONF», Work in Progress5, draft-ietf-netconf-restconf-notif-15, June 2019.

[RFC7049] Bormann, C. and P. Hoffman, «Concise Binary Object Representation (CBOR)», RFC 7049, DOI 10.17487/RFC7049, October 2013, <https://www.rfc-editor.org/info/rfc7049>.

[RFC7540] Belshe, M., Peon, R., and M. Thomson, Ed., «Hypertext Transfer Protocol Version 2 (HTTP/2)», RFC 7540, DOI 10.17487/RFC7540, May 2015, <https://www.rfc-editor.org/info/rfc7540>.

[RFC7923] Voit, E., Clemm, A., and A. Gonzalez Prieto, «Requirements for Subscription to YANG Datastores», RFC 7923, DOI 10.17487/RFC7923, June 2016, <https://www.rfc-editor.org/info/rfc7923>.

[RFC8071] Watsen, K., «NETCONF Call Home and RESTCONF Call Home», RFC 8071, DOI 10.17487/RFC8071, February 2017, <https://www.rfc-editor.org/info/rfc8071>.

[RFC8259] Bray, T., Ed., «The JavaScript Object Notation (JSON) Data Interchange Format», STD 90, RFC 8259, DOI 10.17487/RFC8259, December 2017, <https://www.rfc-editor.org/info/rfc8259>.

[RFC8340] Bjorklund, M. and L. Berger, Ed., «YANG Tree Diagrams», BCP 215, RFC 8340, DOI 10.17487/RFC8340, March 2018, <https://www.rfc-editor.org/info/rfc8340>.

[RFC8640] Voit, E., Clemm, A., Gonzalez Prieto, A., Nilsen-Nygaard, E., and A. Tripathy, «Dynamic Subscription to YANG Events and Datastores over NETCONF», RFC 8640, DOI 10.17487/RFC8640, September 2019, <https://www.rfc-editor.org/info/rfc8640>.

[RFC8641] Clemm, A. and E. Voit, «Subscription to YANG Notifications for Datastore Updates», RFC 8641, DOI 10.17487/RFC8641, September 2019, <https://www.rfc-editor.org/info/rfc8641>.

Приложение A. Пример дополнения настроенного транспорта

В этом приложении представлен ненормативный пример расширения модуля YANG из раздела 4 для встраивания параметров конфигурации, требуемых процессом организации транспортного соединения. Пример не содержит полной модели транспорта и показывает соединение через воображаемый тип транспорта foo. Дополнительные сведения о настройке транспортной связности для настраиваемой подписки приведены в параграфе 2.5.7.

Представленный пример модуля YANG содержит два основных элемента. Первым является идентификатор транспорта foo, который позволяет агенту настройки указать foo в качестве типа транспорта для подписки. Вторым является дополнение YANG case foo через узел /subscriptions/subscription/receivers/receiver, определённый в разделе 4. Это дополнение задаёт параметры настройки транспорта address и port, которые нужны для соединения с получателем.

   module example-foo-subscribed-notifications {
     yang-version 1.1;
     namespace
       "urn:example:foo-subscribed-notifications";

     prefix fsn;

     import ietf-subscribed-notifications {
       prefix sn;
     }
     import ietf-inet-types {
       prefix inet;
     }

     description
       "Указывает foo как поддерживаемый тип транспорта для
        уведомлений по подписке.";

     identity foo {
       base sn:transport;
       description
         "Тип транспорта foo доступен для использования в качестве
          транспортного протокола подписки на уведомления.";
     }

     augment
       "/sn:subscriptions/sn:subscription/sn:receivers/sn:receiver" {
       when 'derived-from(../../../transport, "fsn:foo")';
       description
         "Это дополнение делает доступными для получателя параметры 
          транспорта foo.";
       leaf address {
         type inet:host;
         mandatory true;
         description
           "Задаёт адрес для сообщений, направляемых получателю.";
       }
       leaf port {
         type inet:port-number;
         mandatory true;
         description
           "Задаёт номер порта для сообщений, направляемых получателю.";
       }
     }
   }

Рисунок 21. Пример транспортного дополнения для фиктивного протокола foo.

Этот пример модуля YANG для транспорта foo не предназначен для реального развёртывания. Для реальных транспортных технологий нужно определить соответствующий модуль YANG.

Благодарности

Спасибо Andy Bierman, Tim Jenkins, Martin Bjorklund, Kent Watsen, Balazs Lengyel, Robert Wilton, Sharon Chisholm, Hector Trevino, Susan Hares, Michael Scharf, Guangying Zheng за ценные комментарии, дискуссии и отзывы.

Адреса авторов

Eric Voit
Cisco Systems
Email: evoit@cisco.com
 
Alexander Clemm
Futurewei
Email: ludwig@clemm.org
 
Alberto Gonzalez Prieto
Microsoft
Email: alberto.gonzalez@microsoft.com
 
Einar Nilsen-Nygaard
Cisco Systems
Email: einarnn@cisco.com
 
Ambika Prasad Tripathy
Cisco Systems
Email: ambtripa@cisco.com

Перевод на русский язык

Николай Малых

nmalykh@protokols.ru

1Internet Engineering Task Force — комиссия по решению инженерных задач Internet.

2Internet Engineering Steering Group — комиссия по инженерным разработкам Internet.

3Differentiated Services Code Point — код дифференцированного обслуживания.

4Secure Shell — защищённая оболочка.

5Опубликовано в RFC 8650. Прим. перев.

Рубрика: RFC | Оставить комментарий

RFC 8632 A YANG Data Model for Alarm Management

Internet Engineering Task Force (IETF)                         S. Vallin
Request for Comments: 8632                              Stefan Vallin AB
Category: Standards Track                                   M. Bjorklund
ISSN: 2070-1721                                                    Cisco
                                                          September 2019

A YANG Data Model for Alarm Management

Модель данных YANG для сигналов тревоги

PDF

Аннотация

Этот документ задаёт модуль YANG для управления сигналами тревоги. Модуль включает функции для управления списком сигналов, блокировки аварийных сигналов и уведомления систем управления. Имеются также операции для управления состоянием оператора сигналов тревоги и процедуры административных аварийных сигналов. Модуль сопоставляется с соответствующими стандартами для аварийных сигналов.

Статус документа

Документ относится к категории Internet Standards Track.

Документ является результатом работы IETF1 и представляет согласованный взгляд сообщества IETF. Документ прошёл открытое обсуждение и был одобрен для публикации IESG2. Дополнительную информацию о стандартах Internet можно найти в разделе 2 в RFC 7841.

Информацию о текущем статусе документа, ошибках и способах обратной связи можно найти по ссылке https://www.rfc-editor.org/info/rfc8632.

Авторские права

Авторские права (Copyright (c) 2019) принадлежат IETF Trust и лицам, указанным в качестве авторов документа. Все права защищены.

К документу применимы права и ограничения, указанные в BCP 78 и IETF Trust Legal Provisions и относящиеся к документам IETF (http://trustee.ietf.org/license-info) на момент публикации данного документа. Прочтите эти документы внимательно, поскольку в них описаны права и ограничения, относящиеся к данному документу. Фрагменты программного кода, включённые в документ, распространяются в соответствии с упрощённой лицензией BSD, как указано в параграфе 4.e Trust Legal Provisions, без каких-либо гарантий (как указано в Simplified BSD License).

1. Введение

Этот документ задаёт модуль YANG [RFC7950] для управления сигналами тревоги. Цель состоит в определении стандартизованного интерфейса для аварийных сигналов в сетевых устройствах, который можно легко интегрировать с управляющими приложениями. Модель также применима для северного интерфейса в управляющих приложениях.

Отслеживание аварийных сигналов является важной частью мониторинга сети. Необработанные сигналы от устройств не всегда указывают состояние сетевых служб и первопричину. Возможность передачи сигналов в приложения управления аварийными сигналами в стандартизованном формате является отправной точкой для выполнения высокоуровневых задач обеспечения надёжности сети.

Устройство модуля основано на опыте реализации и применения доступных аварийных сигналов из стандартов ITU [X.733], 3GPP [ALARMIRP] и ANSI [ISA182].

1.1. Термины и обозначения

Ключевые слова необходимо (MUST), недопустимо (MUST NOT), требуется (REQUIRED), нужно (SHALL), не нужно (SHALL NOT), следует (SHOULD), не следует (SHOULD NOT), рекомендуется (RECOMMENDED), не рекомендуется (NOT RECOMMENDED), возможно (MAY), необязательно (OPTIONAL) в данном документе интерпретируются в соответствии с BCP 14 [RFC2119] [RFC8174] тогда и только тогда, когда они выделены шрифтом, как показано здесь.

Ниже перечислены термины, определённые в [RFC7950]:

  • action — действие;
  • client — клиент;
  • data tree — дерево данных;
  • server — сервер.

Этот документ определяет ряд дополнительных терминов.

Alarm (общая концепция) — сигнал тревоги, аварийный сигнал

Указывает нежелательное состояние ресурса, требующее корректировки.

Fault — отказ

Причина нежелательного поведения. Не существует нетривиальной взаимно-однозначной связи между аварийными сигналами и отказами. Один отказ может вызывать несколько сигналов тревоги, если в системе нет возможности определить первопричину и найти корреляции. Для аварийного сигнала может не быть отказа, послужившего причиной. Например, сигнал о неприемлемой средней оценке (Mean Opinion Score или MOS) от зонда Voice over IP (VOIP) в результате неоптимальной настройки качества обслуживания (QoS).

Alarm Type — тип сигнала тревоги

Тип сигнала указывает возможное уникальное состояние тревоги для ресурса. Типы сигналов указываются именами, такими как link-alarm (тревога на канале), jitter-violation (нарушение допустимых вариаций), high-disk-utilization (значительное заполнение диска).

Resource — ресурс

Подробная идентификация связанного с аварийным сигналом ресурса, например, интерфейса или процесса.

Alarm Instance — экземпляр сигнала тревоги

Состояние сигнала тревоги для конкретного ресурса и сигнала, например, GigabitEthernet0/15, link-alarm. Это запись в списке аварийных сигналов.

Cleared Alarm — сброшенный сигнал тревоги

Сигнал тревоги, где система считает состояние нежелательным, сброшен. Оператор не может сбрасывать аварийные сигналы, за это отвечает система. Например, уведомление linkUp может считаться сбросом состояния linkDown.

Closed Alarm — закрытый сигнал тревоги

Операторы могут закрывать сигналы тревоги независимо от сброса сигнала. Закрытый сигнал указывает, что сигнал тревоги не требует внимания, поскольку были выполнены корректирующие действия или сигнал можно игнорировать по другим причинам.

Alarm Inventory — опись сигналов тревоги

Список всех возможных сигналов тревоги в системе.

Alarm Shelving — блокировка сигнала тревоги

Блокировка аварийных сигналов в соответствии с заданным критерием.

Corrective Action — корректировочное действие

Действие, предпринимаемое оператором или программой для минимизации влияния аварийного сигнала или устранения первопричины.

Management System — система управления

Приложение для управления сигналами тревоги, принимающего сигналы, например, клиент системы управления.

System — система

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

Деревья, представленные с этом документе, используют нотацию [RFC8340].

2. Цели

Цели разработки модели данных для аварийных сигналов перечислены ниже.

  • Простота использования. Если система поддерживает этот модуль, её можно легко интегрировать в менеджер аварийных сигналов на основе YANG.

  • Сигналы тревоги представляются как состояния ресурсов, а не дискретные уведомления.

  • Представлено точное определение сигнала тревоги для исключения общих событий, которые не следует пересылать как уведомления о сигналах тревоги.

  • Обеспечивается точная идентификация типов сигналов тревоги и их экземпляров.

  • Системе управления следует поддерживать возможность опроса всех доступных в системе типов аварийных сигналов, т. е. считывания описи сигналов тревоги из системы. Это позвляте подготовить для операторов аварийных сигналов соответствующие инструкции.

  • Выполнены требования при применимости аварийных сигналов (Приложение G. Требования к применимости аварийных сигналов). Хотя стандарты IETF и телекоммуникаций рассматривают аварийные сигналы в основном с точки зрения протоколов, в отрасли обработки имеется несколько опубликованных стандартов, касающихся требований к применимости интерфейса сигналов тревоги (см. [EEMUA] и [ISA182]). Этот документ задаёт требования применимости, а также модель данных YANG.

  • Достижимо сопоставление с [X.733], требуемое для некоторых систем аварийной сигнализации. Тем не менее, некоторые концепции X.733 остаются за пределами базовой модели, чтобы сохранить простоту понимания и размер модели.

3. Концепции модели данных для аварийных сигналов

В этом разделе определены основные концепции модели данных на основе работы Vallin и др. [ALARMSEM].

3.1. Определение сигнала тревоги

Аварийный сигнал указывает нежелательное состояние ресурса системы, требующее корректирующих действий. Из этого определения следует запомнить два основных аспекта.

  1. Основное внимание уделено исключению событий и записи информации в целом. Аварийные сигналы следует применять только для нежелательных сигналов, требующих действий.

  2. Сигналы тревоги указывают состояние ресурса, а не являются уведомлением о смене состояния.

Связь этого определения со стандартами для аварийных сигналов описана в Приложении F.

3.2. Тип сигнала тревоги

Этот документ определяет тип сигналов тревоги с идентификатором и квалификатором alarm-type. Идентификатор alarm-type моделируется отождествлением YANG. С идетификаторами (отождествлениями) YANG можно определять новые типы сигналов тревоги распределенным способом. Идентификаторы YANG являются иерархическими, что позволяет определить иерахию аварийных сигналов. Производителям и органам стандартизации следует задавать свои отождествления alarm-type на основе этого определения.

Использование идентификаторов YANG означает, что все возможные аварийные сигналы идентифицированы во время разработки. Явное объявление типов аварийных сигналов упрощает квалификацию аварийных сигналов, подготовку действий по сигналам и документации.

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

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

Производители и органы стандартизации могут определять свою иерархию alarm-type. Ниже приведён пример иерархии на основе типов событий X.733.

     import ietf-alarms {
       prefix al;
     }
     identity vendor-alarms {
       base al:alarm-type;
     }
     identity communications-alarm {
       base vendor-alarms;
     }
     identity link-alarm {
       base communications-alarm;
     }

Типы аварийных сигналов могут быть абстрактными. Абстрактный тип служит базой для определения иарахии типов сигналов тревоги. Имеется два варианта конкретных типов аварийных сигналов.

  1. Последний подчиненный идентификатор в иерархии alarm-type-id является конкретным, например, alarm-identity.environmental-alarm.smoke. В приведённом примере alarm-identity и environmental-alarm — абстрактные идентификаторы YANG, а smoke — конкретный.

  2. Иерархия идентификаторов YANG является абстрактной, а конкретный тип задан динамической строкой alarm-qualifier, например, alarm-identity.environmental-alarm.external-detector с alarm-type-qualifier smoke.

Пример

     // Вариант 1: конкретный идентификатор типа аварийного сигнала
     import ietf-alarms {
       prefix al;
     }
     identity environmental-alarm {
       base al:alarm-type;
       description "Абстрактный тип сигнала.";
     }
     identity smoke {
       base environmental-alarm;
       description "Конкретный тип сигнала.";
     }

     // Вариант 2: конкретный классификатор типа аварийного сигнала
     import ietf-alarms {
       prefix al;
     }
     identity environmental-alarm {
       base al:alarm-type;
       description "Абстрактный тип сигнала.";
     }
     identity external-detector {
       base environmental-alarm;
       description
         "Абстрактный тип сигнала. Процедура настройки в процессе 
          работы задаёт тип обнаруженного сигнала, сообщаемый в
          alarm-type-qualifier.";
     }

Серверу следует стремиться минимизировать число динамически определяемых типов сигналов тревоги.

3.3. Отождествление связанного с аварийным сигналом ресурса

Крайне важна возможность указать связанный с сигналом тревоги ресурс. Это указание должно быть максимально подробным. Если этот ресурс существует в дереве данных, должен использоваться идентификатор экземпляра с полным путём к объекту.

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

Пример

Аварийный сигнал от устройства может указывать ресурс как /dev:interfaces/dev:interface[dev:name=’FastEthernet1/0′], а в менеджере будет /mgr:devices/mgr:device[mgr:name=’xyz123′]/dev:interfaces/dev:interface[dev:name=’FastEthernet1/0′].

Модуль также разрешает иное именование связанного с сигналом тревоги устройства, если его нет в дереве данных.

3.4. Идентификация экземпляров аварийных сигналов

Основной целью модели данных для сигналов тревоги является устранение неоднозначности сопоставления уведомления о сигнале с обновлением экземпляра аварийного сигнала. В X.733 [X.733] и 3GPP [ALARMIRP] на этот счёт нет ясности. В описываемой модели данных указано, что триплет (ресурс, идентификатор сигнала, классификатор сигнала) соответствует одному экземпляру сигнала тревоги. Это значит, что уведомления о сигнале тревоги для одного ресурса и одного типа сигнала сответствуют обновлению того же экземпляра. Эти три листа служат ключами списка сигналов тревоги.

     list alarm {
       key "resource alarm-type-id alarm-type-qualifier";
       ...
     }

3.5. Жизненный цикл сигнала тревоги

Модель сигналов тревоги чётко разделяет жизненные циклы сигнала в ресурсе, у оператора и административный.

  • Жизненный цикл в ресурсе включет измерение, подающее сигнал, очистку и смену уровня важности.

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

  • Административный жизненный цикл включает очистку (удаление) нежелательных сигналов и сжатие списка изменений состояния сигналов тревоги. Модуль предоставляет операции для управления административным циклом. Сервер может выполнять эти операции на основе своих правил, но это выходит за рамки документа.

Серверу следует описывать, сколь долго он сохраняет сброшенные и закрытые сигналы, пока они не будут удалены вручную или по правилам автоматического удаления. Процедуры для этого выходят за рамки документа.

3.5.1. Жизненный цикл сигнала тревоги в ресурсе

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

  1. Сигналы не удаляются при очистке, удаление является административным процессом. В модуле YANG ietf-alarms задано действие purge-alarms для удаления сигналов тревоги.

  2. Сигналы не очищаются оператором, это может сделать только измеритель. Оператор может закрыть сигнал.

Приведённое ниже представление дерева YANG иллюстрирует ориентированный на ресурсы жизненный цикл сигнала.

     +--ro alarm* [resource alarm-type-id alarm-type-qualifier]
        ...
        +--ro is-cleared                 boolean
        +--ro last-raised                yang:date-and-time
        +--ro last-changed               yang:date-and-time
        +--ro perceived-severity         severity
        +--ro alarm-text                 alarm-text
        +--ro status-change* [time] {alarm-history}?
           +--ro time                    yang:date-and-time
           +--ro perceived-severity      severity-with-clear
           +--ro alarm-text              alarm-text

Для каждого изменения статуса с точки зрения ресурса в список status-change добавляется строка, если сервер реализует функцию alarm-history. Эта функция необязательна для реализации, поскольку сохранение истории аварийных сигналов может влиять на ресурсы памяти сервера.

Последние значения статуса представлены также как листья (leaf) для сигнала тревоги. Отметим, что важность сигнала не включает логического флага cleared.

Таким образом, аварийный сигнал может иметь вид ((«GigabitEthernet0/25», «link-alarm»,»»), false, 2018-04-08T08:20:10.00Z, 2018-04-08T08:20:10.00Z, major, «Interface GigabitEthernet0/25 down»).

3.5.2. Жизненный цикл сигнала тревоги у оператора

Операторы могут применять к сигналам тревоги действие set-operator-state.

     +--ro alarm* [resource alarm-type-id alarm-type-qualifier]
        ...
        +--ro operator-state-change* [time] {operator-actions}?
        |  +--ro time        yang:date-and-time
        |  +--ro operator    string
        |  +--ro state       operator-state
        |  +--ro text?       string
        +---x set-operator-state {operator-actions}?
           +---w input
              +---w state    writable-operator-state
              +---w text?    string

Операторским состоянием для сигнала тревоги может быть none, ack, shelved, closed. Удаление сигнала (действие purge-alarms) может использовать статус сигнала в качестве критерия. Например, закрытым считается сигнал тревоги, для которого оператор выполнил все требуемые действия по исправлению ситуации, поэтому такие сигналы можно очищать (purge).

3.5.3. Административный жизненный цикл сигнала тревоги

Удаление сигналов тревоги из списка считается административным действием purge-alarms, принимающим на входе выражение для фильтра. Фильтр указывает аварийные сигналы на основе жизненного цикла у оператора и в ресурсе, такие как «все сигналы до указанного момента». Сервер также может выполнять операции на основе других правил, но это выходит за рамки документа.

Очищенные сигналы тревоги удаляются из списка. Отметим, что при изменении состояния связанного с сигналом ресурса изменится после очистки, сигнал может снова появиться в списке.

Сигналы тревоги можно сжимать. При этом удаляются все записи списка status-change, кроме последней смены состояния. Клиент может выполнить сжатие с помощью действия compress-alarms. Сервер может выполнять сжатие на основе других правил, но это выходит за рамки документа.

3.6. Первопричина, затронутые ресурсы и сигналы тревоги

Модель данных сигналов тревоги не предъявляет к системе требований по поддержке сопоставлений аварийных сигналов и анализа первопричин или влияния на службы. Однако для случаев поддержки таких функций этот параграф описывает представление такого анализа в модели данных. Эти части модели являются необязательными. Модуль поддерживает три сценария.

Root-cause analysis — анализ первопричины

Сигнал может указывать ресурсы, которые могут быть первопричиной, например, сигнал базы данных о заполнении дискового раздела.

Service-impact analysis — анализ влияния на службы

Сигнал может относиться к затрагиваемым ресурсам, например, аварийный сигнал сетевого интерфейса может говорить о влиянии на сетевые службы.

Alarm correlation — сопоставление аварийных сигналов

Между сигналами могут быть зависимости. Несколько сигналов могут группироваться, например, сигнал потоковой среды, связанный с сигналом о значительных вариациях задержки (high-jitter).

Системы различаются по способности сопоставления и анализа сигналов тревоги и назначение модели данных состоит в том, чтобы поддерживать любую возможность, в том числе их отсутствие.

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

Аварийный сигнал имеет leaf-list для указания возможного impacted-resource и leaf-list для возможного root-cause-resource, которые служат лишь советами. Клиентское приложение может использовать эти сведения для представления общего состояния. В примере с заполненным диском хорошим сигналом будет указание раздела диска в качестве связанного с сигналом ресурса и добавление базы данных и приложений в лист-список impacted-resource.

Системе следует стремиться указать ресурс, на который можно воздействовать, как лист resource. Лист-список impacted-resource нужно использовать для указания побочных влияний сигнала тревоги, поскольку воздействие на эти ресурсы не поможет в решении проблемы. В примере с заполненным диском иллюстрируется этот принцип — проблему невозможно решить с помощью операций базы данных, однако нужно обратить на неё внимание при выполнении операций, ограничивающих влияние проблемы.

В некоторых ситуациях система может быть не способна выявить первопричину — ресурс, на который нужно воздействовать. Измерения в этом случае лишь отслеживают побочные эффекты и выдают сигнал тревоги для указания ситуации, требующей внимания, и могут определить кандидатов на роль ресурса, являющегося первопричиной. В этом случае можно использовать лист-список root-cause-resource для указания таких кандидатов. Примером такого рода сигнала может быть активный инструмент тестирования, который обнаруживает нарушение соглашения об уровне обслуживания (Service Level Agreement или SLA) для соединения VPN и указывает устройства в цепочке, как возможные первопричины.

Модель данных сигналов тревоги поддерживает возможность группировать связанные сигналы в списке related-alarm. Это позволяет серверу информировать клиента о наличии связей между аварийными сигналами.

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

3.7. Блокировка аварийных сигналов

Блокировка (shelving) аварийных сигналов является важной функцией, позволяющей приложениям управления сигналами тревоги и операторам исключить лишние сигналы, путём их игнорирования (блокировки, фильтрации). Игнорируемые сигналы указываются в специальном списке shelved-alarm, позволяющем отфильтровать их, оставляя в основном списке сигналов лишь интересующие записи. Заблокированные сигналы порождают уведомлений, но список shelved-alarm обновляется при любых изменениях состояния сигналов (alarm-state).

Блокировку сигналов тревоги необязательно реализовать, поскольку сопоставление сигналов тревоги с критериями блокировки может влиять на серверные ресурсы обработки.

3.8. Профили аварийных сигналов

Профили аварийных сигналов служат для настройки дополнительных сведений о типе сигнала. Этот модуль поддерживает уровни важности, переопределяющие принятые в системе по умолчанию. Это соответствует функциональности профиля назначения важности сигналов тревоги (Alarm Severity Assignment Profile или ASAP) в M.3100 [M.3100] и M.3160 [M.3160]. Другие стандартные или фирменные модули могут дополнять список сведениями о типах сигналов тревоги.

4. Модель данных

Основными частями модели данных являются список аварийных сигналов alarm-list со связанными уведомлениями и список alarm-inventory со всеми типами возможных сигналов тревоги, которые должны быть реализованы в системе. Остальная часть модели сделана условной с помощью функций YANG (feature) operator-actions, alarm-shelving, alarm-history, alarm-summary, alarm-profile, severity-assignment. Общая структура модели данных приведена ниже.

     +--rw control
     |  +--rw max-alarm-status-changes?   union
     |  +--rw notify-status-changes?      enumeration
     |  +--rw notify-severity-level?      severity
     |  +--rw alarm-shelving {alarm-shelving}?
     |        ...
     +--ro alarm-inventory
     |  +--ro alarm-type* [alarm-type-id alarm-type-qualifier]
     |        ...
     +--ro summary {alarm-summary}?
     |  +--ro alarm-summary* [severity]
     |  |     ...
     |  +--ro shelves-active?   empty {alarm-shelving}?
     +--ro alarm-list
     |  +--ro number-of-alarms?   yang:gauge32
     |  +--ro last-changed?       yang:date-and-time
     |  +--ro alarm* [resource alarm-type-id alarm-type-qualifier]
     |  |     ...
     |  +---x purge-alarms
     |  |     ...
     |  +---x compress-alarms {alarm-history}?
     |        ...
     +--ro shelved-alarms {alarm-shelving}?
     |  +--ro number-of-shelved-alarms?      yang:gauge32
     |  +--ro shelved-alarms-last-changed?   yang:date-and-time
     |  +--ro shelved-alarm*
     |  |       [resource alarm-type-id alarm-type-qualifier]
     |  |     ...
     |  +---x purge-shelved-alarms
     |  |     ...
     |  +---x compress-shelved-alarms {alarm-history}?
     |        ...
     +--rw alarm-profile*
             [alarm-type-id alarm-type-qualifier-match resource]
             {alarm-profile}?
        +--rw alarm-type-id                        alarm-type-id
        +--rw alarm-type-qualifier-match           string
        +--rw resource                             resource-match
        +--rw description                          string
        +--rw alarm-severity-assignment-profile
                {severity-assignment}?
              ...

4.1. Управление аварийными сигналами

Лист /alarms/control/notify-status-changes указывает, следует передавать уведомления для любой смены состояния, только для активации, только для очистки или только при превышении заданного уровня важности. Эта функция в сочетании с блокировкой сигналов тревоги соответствует функциям ITU Alarm Report Control (Приложение F.2.4).

Каждый сигнал тревоги имеет список смены состояний. Размер этого списка задает /alarms/control/max-alarm-status-changes. При заполненном списке создание новой записи удаляет самую старую.

4.1.1. Блокирование сигналов тревоги

Ниже показано дерево управления блокировкой сигналов тревоги.

     +--rw control
        +--rw alarm-shelving {alarm-shelving}?
           +--rw shelf* [name]
              +--rw name           string
              +--rw resource*      resource-match
              +--rw alarm-type*
              |       [alarm-type-id alarm-type-qualifier-match]
              |  +--rw alarm-type-id                 alarm-type-id
              |  +--rw alarm-type-qualifier-match    string
              +--rw description?   string

Заблокированные сигналы указываются в отдельном списке shelved-alarm. Соответствующие сигналы тревоги должны указываться в списке /alarms/shelved-alarms/shelved-alarm, а прочие должны помещаться в /alarms/alarm-list/alarm. Сервер не передаёт уведомлений для заблокированных сигналов.

Установка и снятие блокировки выполняются только редактированием конфигурации блокировки и невозможны для отдельного сигнала тревоги. Сервер добавляет состояние у оператора, связанное с блокировкой сигналов тревоги.

Лист /alarms/summary/shelves-active в сводке сигналов тревоги указывает, были ли сигналы экранированы.

Система не обязана поддерживать функцию экранирования.

4.2. Опись сигналов тревоги

Опись (inventory) аварийных сигналов представляет все типы сигналов тревоги, возможных в системе. Система управления может применять этот список для организации процедур обработки. Причины актуальности описи сигналов указаны ниже.

  • Ссистема может не реализовать все указанные идентификаторы типов сигналов тревоги, а некоторые идентификаторы являются абстрактными.

  • В системе настроены динамические типы сигналов с использованием классификаторов. Опись позволяет системе управления найти такие типы.

Отметим, что механизм добавления динамических типов сигналов должен добавлять их в эту опись.

Необязательный лист resource в описи аварийных сигналов позволяет системе публиковать сведения о ресурсах, к которым может относиться данный тип сигналов тревоги.

Сервер должен реализовать опись аварийных сигналов для поддержки управляемых процедур обработки у клиентов.

Разработчики сервера могут документировать опись аварийных сигналов для автономной обработки клиентами. Для этого можно использовать формат файла из [YANG-INSTANCE]. Ниже приведено дерево описи аварийных сигналов.

     +--ro alarm-inventory
        +--ro alarm-type* [alarm-type-id alarm-type-qualifier]
           +--ro alarm-type-id           alarm-type-id
           +--ro alarm-type-qualifier    alarm-type-qualifier
           +--ro resource*               resource-match
           +--ro will-clear              boolean
           +--ro severity-level*         severity
           +--ro description             string

4.3. Сводка сигналов тревоги

В сводном списке содержатся аварийные сигналы по их важности — число очищенных, очищенных и закрытых, закрытых. Указывается также наличие заблокированных сигналов. Дерево сводного списка сигналов приведено ниже.

     +--ro summary {alarm-summary}?
        +--ro alarm-summary* [severity]
        |  +--ro severity                  severity
        |  +--ro total?                    yang:gauge32
        |  +--ro not-cleared?              yang:gauge32
        |  +--ro cleared?                  yang:gauge32
        |  +--ro cleared-not-closed?       yang:gauge32
        |  |       {operator-actions}?
        |  +--ro cleared-closed?           yang:gauge32
        |  |       {operator-actions}?
        |  +--ro not-cleared-closed?       yang:gauge32
        |  |       {operator-actions}?
        |  +--ro not-cleared-not-closed?   yang:gauge32
        |          {operator-actions}?
        +--ro shelves-active?   empty {alarm-shelving}?

4.4. Список аварийных сигналов

Список сигналов тревоги /alarms/alarm-list является функцией от тройки (resource, alarm type, alarm-type qualifier) до текущего состояния сигнала. Композитное состояние включает состояния жизненного цикла сигнала в ресурсе, флага очистки и состояния у оператора, такие как подтверждения. Это означает, что для данного ресурса и типа сигнала список показывает текущие состояния сигналов тревоги, такие как подтверждение и очистка.

   +--ro alarm-list
      +--ro number-of-alarms?   yang:gauge32
      +--ro last-changed?       yang:date-and-time
      +--ro alarm* [resource alarm-type-id alarm-type-qualifier]
      |  +--ro resource                 resource
      |  +--ro alarm-type-id            alarm-type-id
      |  +--ro alarm-type-qualifier     alarm-type-qualifier
      |  +--ro alt-resource*            resource
      |  +--ro related-alarm*
      |  |       [resource alarm-type-id alarm-type-qualifier]
      |  |       {alarm-correlation}?
      |  |  +--ro resource
      |  |  |       -> /alarms/alarm-list/alarm/resource
      |  |  +--ro alarm-type-id           leafref
      |  |  +--ro alarm-type-qualifier    leafref
      |  +--ro impacted-resource*       resource
      |  |       {service-impact-analysis}?
      |  +--ro root-cause-resource*     resource
      |  |       {root-cause-analysis}?
      |  +--ro time-created             yang:date-and-time
      |  +--ro is-cleared               boolean
      |  +--ro last-raised              yang:date-and-time
      |  +--ro last-changed             yang:date-and-time
      |  +--ro perceived-severity       severity
      |  +--ro alarm-text               alarm-text
      |  +--ro status-change* [time] {alarm-history}?
      |  |  +--ro time                  yang:date-and-time
      |  |  +--ro perceived-severity    severity-with-clear
      |  |  +--ro alarm-text            alarm-text
      |  +--ro operator-state-change* [time] {operator-actions}?
      |  |  +--ro time        yang:date-and-time
      |  |  +--ro operator    string
      |  |  +--ro state       operator-state
      |  |  +--ro text?       string
      |  +---x set-operator-state {operator-actions}?
      |  |  +---w input
      |  |     +---w state    writable-operator-state
      |  |     +---w text?    string
      |  +---n operator-action {operator-actions}?
      |     +-- time        yang:date-and-time
      |     +-- operator    string
      |     +-- state       operator-state
      |     +-- text?       string
      +---x purge-alarms
      |  +---w input
      |  |  +---w alarm-clearance-status    enumeration
      |  |  +---w older-than!
      |  |  |  +---w (age-spec)?
      |  |  |     +--:(seconds)
      |  |  |     |  +---w seconds?   uint16
      |  |  |     +--:(minutes)
      |  |  |     |  +---w minutes?   uint16
      |  |  |     +--:(hours)
      |  |  |     |  +---w hours?     uint16
      |  |  |     +--:(days)
      |  |  |     |  +---w days?      uint16
      |  |  |     +--:(weeks)
      |  |  |        +---w weeks?     uint16
      |  |  +---w severity!
      |  |  |  +---w (sev-spec)?
      |  |  |     +--:(below)
      |  |  |     |  +---w below?   severity
      |  |  |     +--:(is)
      |  |  |     |  +---w is?      severity
      |  |  |     +--:(above)
      |  |  |        +---w above?   severity
      |  |  +---w operator-state-filter! {operator-actions}?
      |  |     +---w state?   operator-state
      |  |     +---w user?    string
      |  +--ro output
      |     +--ro purged-alarms?   uint32
      +---x compress-alarms {alarm-history}?
         +---w input
         |  +---w resource?               resource-match
         |  +---w alarm-type-id?
         |  |       -> /alarms/alarm-list/alarm/alarm-type-id
         |  +---w alarm-type-qualifier?   leafref
         +--ro output
            +--ro compressed-alarms?   uint32

У каждого аварийного сигнала есть три важных состояния — очистка для ресурса is-cleared, воспринимаемый уровень важности perceived-severity и состояние оператора, доступное в списке operator-state.

История сигналов тревоги для смены состояний в ресурсах хранится в списке status-change, а история состояний у оператора — в списке operator-state-change.

4.5. Список заблокированных сигналов

Структура списка shelved-alarm совпадает с описанной выше. Он содержит аварийные сигналы, соответствующие критерию блокировки из /alarms/control/alarm-shelving.

4.6. Профили сигналов

Профиль аварийных сигналов /alarms/alarm-profile является списком настраиваемых типов сигналов тревоги. Этот список поддерживает указание уровней важности в контейнере alarm-severity-assignment-profile. Если аварийный сигнал соответствует настроенному типу, он должен использовать заданный уровень важности вместо принятого в системе по умолчанию. Конфигурация должна также представляться в сводке аварийных сигналов.

     +--rw alarm-profile*
             [alarm-type-id alarm-type-qualifier-match resource]
             {alarm-profile}?
        +--rw alarm-type-id                        alarm-type-id
        +--rw alarm-type-qualifier-match           string
        +--rw resource                             resource-match
        +--rw description                          string
        +--rw alarm-severity-assignment-profile
                {severity-assignment}?
           +--rw severity-level*    severity

4.7. Операции

Модель данных для сигналов тревоги поддерживает указанные ниже действия для управления этими сигналами.

/alarms/alarm-list/purge-alarms

Удаление сигналов из alarm-list по заданному критерию, например, все сброшенные сигналы до указанной даты.

/alarms/alarm-list/compress-alarms

Сжатие списка аварийных сигналов status-change.

/alarms/alarm-list/alarm/set-operator-state

Смена состояния сигнала у оператора, например, сигнал можно подтвердить, установив статус ack.

/alarms/shelved-alarm-list/purge-shelved-alarms

Удаление сигналов из shelved-alarm-list по заданному критерию, например, все сброшенные сигналы до указанной даты.

/alarms/shelved-alarm-list/compress-shelved-alarms

Сжатие списка status-change для аварийных сигналов.

4.8. Уведомления

Модель данных для сигналов тревоги поддерживает базовое уведомление о смене статуса — alarm-state. Оно включает параметры, нужные приложениям, работающим с аварийными сигналами.

Имеется также уведомление для информирования смены оператором статуса сигнала, например, о подтверждении.

При смене сводки сигналов тревоги, например, вставке платы нового типа, уведомление будет информировать управляющие приложения о доступности нового типа сигналов тревоги.

5. Связь с модулем YANG ietf-hardware

В RFC 8348 [RFC8348] задан модуль YANG ietf-hardware для управления оборудованием. Узел alarm-state в RFC 8348 содержит сводку уровней важности, которые могут быть активны для соответствующего оборудования, но ничего не говорит о способах информирования при авариях и не включает деталей аварийных сигналов.

Ниже показано сопоставление префикса al в этой модели данных и с alarm-state и префиксом hw в RFC 8348.

al:resource

Соответствует записи списка /hw:hardware/hw:component/.

al:is-cleared

Бит в /hw:hardware/hw:component/hw:state/hw:alarm-state не установлен.

al:perceived-severity

Соответствующий бит в /hw:hardware/hw:component/hw:state/hw:alarm-state установлен.

al:operator-state-change/al:state

Если сигнал подтверждён оператором, устанавливается бит hw:under-repair в /hw:hardware/hw:component/hw:state/hw:alarm-state.

6. Модуль YANG для сигналов тревоги

Этот модуль YANG ссылается на [RFC6991] и [XSD-TYPES].

  <CODE BEGINS> file "ietf-alarms@2019-09-11.yang"
  module ietf-alarms {
    yang-version 1.1;
    namespace "urn:ietf:params:xml:ns:yang:ietf-alarms";
    prefix al;

    import ietf-yang-types {
      prefix yang;
      reference
        "RFC 6991: Common YANG Data Types.";
    }

    organization
      "IETF CCAMP Working Group";
    contact
      "WG Web:   <https://trac.ietf.org/trac/ccamp> 
       WG List:  <mailto:ccamp@ietf.org> 

       Editor:   Stefan Vallin
                 <mailto:stefan@wallan.se> 

       Editor:   Martin Bjorklund
                 <mailto:mbj@tail-f.com>"; 
    description
      "Этот модуль задаёт интерфейс для управления сигналами тревоги. 
       Основными источниками для создания модуля послужили стандарты 
       3GPP Alarm IRP, ITU-T X.733, ANSI/ISA-18.2.

       Основные функции модуля указаны ниже.
         * Список аварийных сигналов. Сброшенные сигналы остаются в
           списке, пока не будут явно очищены.
         * Действия оператора по сигналу - подтверждение и закрытие.
         * Административные действия по сигналы - очистка списка
           сигналов в соответствии с конкретными критериями.
         * Опись сигналов - управляющее приложение может считывать все
           сигналы, реализованные системой.
         * Блокировка (экранирование) сигналов в соответствии с
           конкретными критериями.
         * Профили сигналов. Система управления может связывать с типом
           сигнала дополнительные сведения, например, переопределять
           принятый по умолчанию в системе уровень важности.

       Этот модуль использует представление аварийных сигналов с учётом
       состояния. Сигнал является состоянием конкретного ресурса 
       (отметим, что сигнал не является уведомлением). Типом сигнала
       является возможное состояние сигнала для ресурса. Например,
               ('link-alarm', 'GigabitEthernet0/25')
       является сигналом типа link-alarm на ресурсе GigabitEthernet0/25.

       Типы сигналов тревоги указываются идентификаторами YANG и
       необязательными строковыми классификаторами, которые позволяют
       динамически расширять статический набор типов сигналов. Типы
       сигналов указывают возможное состояние тревоги, а не отдельные
       уведомления. Например, традиционные уведомления link-down и
       link-up относятся к одному типу аварийных сигналов (link-alarm).

       При таком устройстве не возникает неоднозначности сопоставления
       аварийных сигналов и их сброса. Уведомления для одного ресурса и
       типа сигнала считаются обновлениями одного сигнала, например,
       очисткой активного сигнала или сменой уровня важности. Измерения
       могут менять уровень важности и текст имеющегося аварийного
       сигнала. Упомянутый выше пример сигнала может иметь вид
       example can therefore look like the following:

         (('link-alarm', 'GigabitEthernet0/25'), warning,
          'interface down while interface admin state is up')

       Чётко отделено обновление сигнала тревоги от базового ресурса,
       подобно очистке и обновлениям от оператора, например, при
       подтверждении или закрытии аварийного сигнала
         (('link-alarm', 'GigabitEthernet0/25'), warning,
          'interface down while interface admin state is up', cleared,
          closed)

       Поддерживаются административные действия, такие как удаление
       закрытых сигналов тревоги старше указанного возраста.

       Этот модуль YANG не задаёт обнаружение и сброс конкретных
       сигналов тревоги средствами измерения. Этот вопрос решают органы
       стандартизации (SDO) и предприятия, владеющие технологией.

       Ключевые слова ДОЛЖНО, НЕДОПУСТИМО, ТРЕБУЕТСЯ, НУЖНО, НЕ НУЖНО, 
       СЛЕДУЕТ, НЕ СЛЕДУЕТ, РЕКОМЕНДУЕТСЯ, НЕ РЕКОМЕНДУЕТСЯ, МОЖНО,
       НЕОБЯЗАТЕЛЬНО в этом документе трактуются в соответствии с 
       BCP 14 (RFC 2119) (RFC 8174) тогда и только тогда, когда они
       указаны заглавными буквами, как показано здесь.

       Авторские права (Copyright (c) 2019) принадлежат IETF Trust и
       лицам, указанным как авторы. Все права защищены.

       Распространение и применение модуля в исходной или двоичной 
       форме с изменениями или без таковых разрешено в соответствии с
       лицензией Simplified BSD License, изложенной в параграфе 4.c
       IETF Trust's Legal Provisions Relating to IETF Documents
       (https://trustee.ietf.org/license-info). 

       Эта версия модуля YANG является частью RFC 8632, где правовые
       аспекты приведены более полно.";

    revision 2019-09-11 {
      description
        "Исходный выпуск.";
      reference
        "RFC 8632: A YANG Data Model for Alarm Management";
    }

    /*
     * Свойства (функции)
     */

    feature operator-actions {
      description
        "Указывает, что система поддерживает состояния аварийных
         сигналов у оператора.";
    }

    feature alarm-shelving {
      description
        "Указывает, что система поддерживает блокировку сигналов.
         Блокировка может влиять на ресурсы обработки на сервере
         из-за сопоставления сигналов с критериями блокировки.";
    }

    feature alarm-history {
      description
        "Указывает, что сервер поддерживает историю смены состояний для
         каждого аварийного сигнала. Например, при 10-кратных переходах 
         между cleared и active это будет представлено отдельным списком
         для аварийного сигнала. Сохранение истории может влиять на
         используемые сервером ресурсы памяти.";
    }

    feature alarm-summary {
      description
        "Указывает, что сервер поддерживает сводку аварийных сигналов по
         уровню важности и состоянию у оператора.";
    }

    feature alarm-profile {
      description
        "Система позволяет клиентам настраивать дополнительную
         информацию для каждого типа сигналов тревоги.";
    }

    feature severity-assignment {
      description
        "Система поддерживает настраиваемые уровни важности сигналов.";
      reference
        "ITU-T Recommendation M.3100:
           Generic network information model
         ITU-T Recommendation M.3160:
           Generic, protocol-neutral management information model";
    }

    feature root-cause-analysis {
      description
        "Система поддерживает идентификацию ресурсов-кандидатов для
         первопричины сигнала тревоги, например, дисковый раздел для
         сигнала об отказе регистрации в системном журнале.";
    }

    feature service-impact-analysis {
      description
        "Система поддерживает идентификацию ресурсов, которые могут
         быть затронуты аварийным сигналом, например, смена состояния
         канала может указывать воздействие на канал.";
    }

    feature alarm-correlation {
      description
        "Система поддерживает сопоставление и группировку сигналов.";
    }

    /*
     * Идентификаторы (отождествления)
     */

    identity alarm-type-id {
      description
        "Базовый идентификатор типа аварийного сигнала, однозначно 
         указывающий сигнал тревоги без указания ресурса. Один тип
         может относится к разным ресурсам. Если ресурс сообщает один и
         тот же тип сигнала, это считается тем же сигналом. Тип сигнала
         является упрощением различных механизмов сопоставления X.733 и 
         3GPP Alarm IRP и допускает иерархическое расширение.

         К идентификатору может добавляться строковый классификатор,  
         чтобы различать типы аварийных сигналов на основе сведений, 
         неизвестных в момент разработки, таких как значения в тексте
         привязок переменных SNMP Notification.

         Стандарты и производители могут задавать субидентификаторы
         для указания конкретных типов аварийных сигналов.

         Этот идентификатор является абстракцией и его НЕДОПУСТИМО
         применять для конкретных сигналов тревоги.";
    }

    /*
     * Базовые типы
     */

    typedef resource {
      type union {
        type instance-identifier {
          require-instance false;
        }
        type yang:object-identifier;
        type string;
        type yang:uuid;
      }
      description
        "Это указание ресурса, с которым связан сигнал тревоги, такого
         как интерфейс. Это указание следует делать подробным, чтобы
         направить оператора и обеспечить уникальность сигналов.

         Если затронутый интерфейс моделируется в YANG, это может быть
         instance-identifier. Если ресурс является объектом SNMP, типом
         будет object-identifier. Для прочих ресурсов, например,
         отличительного пути в базовой информационной модели (Common 
         Information Model или CIM) этот тип будет строкой.

         Если связанный с сигналом ресурс указан UUID, применяется тип
         uuid. Этот тип следует применять с осторожностью, поскольку
         оператору сложно работать со значениями UUID.

         Если сервер поддерживает несколько моделей, следует применять
         предпочтения в порядке из определения объединения (union).";
    }

    typedef resource-match {
      type union {
        type yang:xpath1.0;
        type yang:object-identifier;
        type string;
      }
      description
        "Этот тип служит для сопоставления ресурса с типом resource.
         Поскольку тип resource является объединением (union) разных 
         типов, resource-match будет объединением соответствующих типов.

         Если тип задан выражением XPath 1.0, ресурс типа
         instance-identifier будет соответствовать, когда экземпляр
         входит в набор узлов, заданный выражением XPath 1.0. Например,
          /ietf-interfaces:interfaces/ietf-interfaces:interface
              [ietf-interfaces:type='ianaift:ethernetCsmacd']
         будет соответствовать ресурсу instance-identifier
          /if:interfaces/if:interface[if:name='eth1'],
         при условии, что eth1 имеет тип ianaift:ethernetCsmacd.

         Если тип задан идентификатором объекта, ресурс типа
         object-identifier будет соответствовать, когда идентификатор 
         объекта является префиксом идентификатора объекта для ресурса
         Например, значению 1.3.6.1.2.1.2.2 будет соответствовать 
         идентификатор ресурса 1.3.6.1.2.1.2.2.1.1.5.

         Если тип задан UUID или строкой, он интерпретируется как
         регулярное выражение XML Schema, которому соответствует ресурс
         типа yang:uuid или string при соответствии регулярного 
         выражения строке ресурса.

         Если тип задан выражением XPath, оно оценивается в описанном
         ниже контексте XPath
           -  Набором объявлений пространств имён служит набор пар
              (префикс, пространство имён) для всех модулей YANG,
              реализованных сервером, где префиксом является имя модуля 
              YANG, а пространство имён определяет оператор namespace в
              модуле YANG.
              Если лист этого типа кодируется в XML, все объявления
              пространств имён в области действия листа добавляются в 
              набор объявлений пространств имён. Если найденный в XML
              префикс уже имеется в наборе объявлений, используется
              пространство имён в XML.
           -  Набор привязок переменных пуст.
           -  Библиотекой функций является библиотека функций ядра
              и функции заданы в разделе 10 RFC 7950.
           -  Узлом контекста является корень дерева данных.";
      reference
        "XML Schema Part 2: Datatypes Second Edition,
           World Wide Web Consortium Recommendation
           REC-xmlschema-2-20041028";
    }

    typedef alarm-text {
      type string;
      description
        "Строка для информирования оператора о сигнале тревоги, которая
         ДОЛЖНА содержать сведения, позволяющие оператору понять и
         устранить проблему. Если строка имеет структуру, она должна 
         быть чётко документирована, чтобы информацию можно было
         проанализировать.";
    }

    typedef severity {
      type enumeration {
        enum indeterminate {
          value 2;
          description
            "Уровень важности не удаётся определить. СЛЕДУЕТ избегать
             этого значения.";
        }
        enum warning {
          value 3;
          description
            "Уровень warning (предупреждение) показывает обнаружение
             потенциальной или предстоящей неполадки до того, как будут
             ощутимы значимые последствия. Следует принять меры для 
             дальнейшей диагностики (при необходимости) и устранения 
             проблемы, чтобы не возникло более серьёзных неполадок,
             влияющих на службы.";
        }
        enum minor {
          value 4;
          description
            "Уровень minor (незначительный) указывает наличие отказа,
             не влияющего на службы. Следует принять меры предотвращения
             более серьёзного отказа (например, влияющего на службы).
             Такой уровень можно указывать, например, при обнаружении
             условий, которые пока не сокращают возможности ресурса.";
        }
        enum major {
          value 5;
          description
            "Уровень major (важный) указывает условия, влияющие на 
             службы и требующие срочного исправления. Такой уровень 
             может указываться при серьёзном ухудшении возможностей
             ресурса, когда требуется восстановление работоспособности";
        }
        enum critical {
          value 6;
          description
            "Уровень critical (критический) указывает серьёзное влияние
             на сервис, требующее немедленных действий по исправлению.
             Такой уровень может указываться, когда ресурс не способен
             работать и требует быстрого восстановления.";
        }
      }
      description
        "Уровень важности сигнала тревоги. Отметим, что значение clear
         не включено. Очистка сигнала указывается логическим флагом.";
      reference
        "ITU-T Recommendation X.733: Information Technology
           - Open Systems Interconnection
           - System Management: Alarm Reporting Function";
    }

    typedef severity-with-clear {
      type union {
        type enumeration {
          enum cleared {
            value 1;
            description
              "Сигнал очищен административно.";
          }
        }
        type severity;
      }
      description
        "Уровень важности сигнала с включением очистки. Применяется лишь
         в уведомлениях о смене состояний аварийных сигналов.";
    }

    typedef writable-operator-state {
      type enumeration {
        enum none {
          value 1;
          description
            "За сигналом не следят.";
        }
        enum ack {
          value 2;
          description
            "За сигналом наблюдают, корректирующие действия не 
             выполнялись или завершились отказом";
        }
        enum closed {
          value 3;
          description
            "Корректирующие действия успешны.";
        }
      }
      description
        "Сообщение оператора о сигнале. Состояние closed указывает, что 
         оператор считает тревогу устранённой. Это отделено от листа
         is-cleared для сигнала тревоги.";
    }

    typedef operator-state {
      type union {
        type writable-operator-state;
        type enumeration {
          enum shelved {
            value 4;
            description
              "Сигнал блокируется. Сигналам в /alarms/shelved-alarms/
               сервер ДОЛЖЕН назначать это состояние у оператора как
               последнюю запись в списке operator-state-change. В текст
               этой записи СЛЕДУЕТ включать имя блокировки.";
          }
          enum un-shelved {
            value 5;
            description
              "Сигнал возвращён в alarm-list после блокировки. Сигналам,
               перенесенным из /alarms/shelved-alarms/ в
               /alarms/alarm-list, сервер ДОЛЖЕН назначать этот статус
               как последнюю запись в списке operator-state-change. В
               текст записи СЛЕДУЕТ включать имя блокировки.";
          }
        }
      }
      description
        "Состояния сигнала у оператора. Статус closed показывает, что
         оператор считает проблему решённой. Это отличается от листа
         is-cleared для аварийного сигнала.";
    }

    /* Типы сигналов тревоги */

    typedef alarm-type-id {
      type identityref {
        base alarm-type-id;
      }
      description
        "Идентификатор типа сигнала тревоги. Описание идентификатора
         ДОЛЖНО указывать, является ли этот тип абстрактным. Абстрактные
         типы служат базой для остальных и не применяются как значения
         сигналов и не включаются в сводку сигналов тревоги.";
    }

    typedef alarm-type-qualifier {
      type string;
      description
        "Если сигнал не может быть полностью задан во время разработки
         значением alarm-type-id, этот строковый классификатор служит 
         для полного определения уникального типа аварийного сигнала.

         Определение классификаторов сигналов считается частью измерения
         и выходит за рамки этого модуля. При использовании как части
         ключа, указывается пустая строка.";
    }

    /*
     * Группировки
     */

    grouping common-alarm-parameters {
      description
        "Базовые параметры сигнала тревоги. Эта группа применяется в
         списке сигналов и уведомлениях о смене alarm-state.";
      leaf resource {
        type resource;
        mandatory true;
        description
          "Связанный с сигналом тревоги ресурс, см. также alt-resource.
           Это может быть, например, ссылка на интерфейс с аварией";
      }
      leaf alarm-type-id {
        type alarm-type-id;
        mandatory true;
        description
          "Этот лист вместе с alarm-type-qualifier обеспечивает 
           однозначное указание типа аварийного сигнала.";
      }
      leaf alarm-type-qualifier {
        type alarm-type-qualifier;
        description
          "Этот лист применяется, когда alarm-type-id не может 
           однозначно указать тип сигнала. Обычно это не так и лист
           является пустой строкой.";
      }
      leaf-list alt-resource {
        type resource;
        description
          "Используется при доступности вызвавшего тревогу ресурса через
           другие интерфейсы. Поле может содержать SNMP OID, пути CIM,
           отличительные имена 3GPP и др.";
      }
      list related-alarm {
        if-feature "alarm-correlation";
        key "resource alarm-type-id alarm-type-qualifier";
        description
          "Указывает связанные сигналы тревоги. Отметим, что связанный
           сигнал может быть удалён из списка сигналов тревоги.";
        leaf resource {
          type leafref {
            path "/alarms/alarm-list/alarm/resource";
            require-instance false;
          }
          description
            "Связанный с тревогой ресурс для аварийного сигнала.";
        }
        leaf alarm-type-id {
          type leafref {
            path "/alarms/alarm-list/alarm"
               + "[resource=current()/../resource]"
               + "/alarm-type-id";
            require-instance false;
          }
          description
            "Идентификатор типа сигнала тревоги.";
        }
        leaf alarm-type-qualifier {
          type leafref {
            path "/alarms/alarm-list/alarm"
               + "[resource=current()/../resource]"
               + "[alarm-type-id=current()/../alarm-type-id]"
               + "/alarm-type-qualifier";
            require-instance false;
          }
          description
            "Классификатор для сигнала тревоги.";
        }
      }
      leaf-list impacted-resource {
        if-feature "service-impact-analysis";
        type resource;
        description
          "Ресурсы, на которые может влиять этот сигнал. Если система
           создаёт сигнал для ресурса и сопоставляет его с ресурсами, на
           которые сигнал может влиять, такие ресурсы могут быть указаны 
           здесь. За счёт этого система может создавать один аварийный
           сигнал вместо нескольких. Например, при возникновении сигнала
           для интерфейса impacted-resource может указывать каналы
           агрегированного порта.";
      }
      leaf-list root-cause-resource {
        if-feature "root-cause-analysis";
        type resource;
        description
          "Ресурсы, с которыми может быть связан этот сигнал. Если в 
           системе есть механизм определения первопричины сигнала, этот
           leaf-list может служить для перечисления ресурсов, которые 
           могут служить первопричиной. За счёт этого система может
           создавать один сигнал вместо нескольких. Примером может
           служить отказ системного журнала, когда сигнал указывает
           файловую систему в root-cause-resource. Отметим, что 
           предусмотренное использование не состоит в отправке сигнала
           с указанием root-cause-resource как связанного с тревогой
           ресурса. Лист-список root-cause-resource служит подсказкой
           и не следует создавать сигнал для той же проблемы.";
      }
    }

    grouping alarm-state-change-parameters {
      description
        "Параметры для сены alarm-state. Эта группа применяется в списке
         status-change списка сигналов тревоги и в уведомлениях о смене
         alarm-state.";
      leaf time {
        type yang:date-and-time;
        mandatory true;
        description
          "Время изменения статуса сигнала тревоги. Значение указывает
           фактическое время смены alarm-state в ресурсе, а не момент 
           добавления в список аварийных сигналов. Это же значение 
           ДОЛЖНО указываться в /alarm-list/alarm/last-changed.";
      }
      leaf perceived-severity {
        type severity-with-clear;
        mandatory true;
        description
          "Важность сигнала в соответствии с X.733. Отметим, что это
           может не быть исходным уровнем, поскольку важность сигнала
           может меняться.";
        reference
          "ITU-T Recommendation X.733: Information Technology
             - Open Systems Interconnection
             - System Management: Alarm Reporting Function";
      }
      leaf alarm-text {
        type alarm-text;
        mandatory true;
        description
          "Текст описания смены alarm-state для пользователя.";
        reference
          "ITU-T Recommendation X.733: Information Technology
             - Open Systems Interconnection
             - System Management: Alarm Reporting Function";
      }
    }

    grouping operator-parameters {
      description
        "Параметры, которые может изменить оператор.";
      leaf time {
        type yang:date-and-time;
        mandatory true;
        description
          "Метка времени для действия оператора по сигналу.";
      }
      leaf operator {
        type string;
        mandatory true;
        description
          "Имя оператора, действовавшего по сигналу.";
      }
      leaf state {
        type operator-state;
        mandatory true;
        description
          "Представление оператора о статусе сигнала тревоги.";
      }
      leaf text {
        type string;
        description
          "Дополнительные текстовые сведения от оператора.";
      }
    }

    grouping resource-alarm-parameters {
      description
        "Параметры сигнала тревоги с точки зрения ресурса.";
      leaf is-cleared {
        type boolean;
        mandatory true;
        description
          "Указывает текущее состояние очистки сигнала тревоги. Сигнал
           может перейти из active в cleared и наоборот.";
      }
      leaf last-raised {
        type yang:date-and-time;
        mandatory true;
        description
          "Сигнал может менять уровень важности и переключаться между
           active и cleared в течение срока действия. Этот лист 
           указывает время последней активации (is-cleared = false).";
      }
      leaf last-changed {
        type yang:date-and-time;
        mandatory true;
        description
          "Метка времени последнего изменения списка status-change или
           operator-state-change.";
      }
      leaf perceived-severity {
        type severity;
        mandatory true;
        description
          "Последний уровень важности аварийного сигнала. Если сигнал
           был подан с уровнем warning, а позднее получил уровень major,
           значением листа будет major.";
      }
      leaf alarm-text {
        type alarm-text;
        mandatory true;
        description
          "Текст последнего сообщённого сигнала, . В этот текст следует
           включать сведения, позволяющие оператору понять и устранить
           problem and how to resolve it.";
      }
      list status-change {
        if-feature "alarm-history";
        key "time";
        min-elements 1;
        description
          "Список событий status-change для этого сигнала тревоги.

           Запись с последней меткой времени в этом списке ДОЛЖНА
           соответствовать листьям is-cleared, perceived-severity,
           alarm-text для сигнала.

           Список упорядочивается по меткам времени смены статуса
           сигнала тревоги, начиная с самой старой метки.

           В список включаются указанные ниже смены состояния
           - смена уровня важности (warning, minor, major, critical)
           - смена статуса очистки (обновляется также is-cleared)
           - обновление alarm-text.";
        uses alarm-state-change-parameters;
      }
    }

    grouping filter-input {
      description
        "Группировка для фильтров сведений о сигналах тревоги.";
      leaf alarm-clearance-status {
        type enumeration {
          enum any {
            description
              "Игнорировать статус очистки сигнала тревоги.";
          }
          enum cleared {
            description
              "Фильтровать очищенные аварийные сигналы.";
          }
          enum not-cleared {
            description
              "Фильтровать неочищенные аварийные сигналы.";
          }
        }
        mandatory true;
        description
          "Очистка статуса аварийного сигнала.";
      }
      container older-than {
        presence "Указание возраста";
        description
          "Соответствие листу last-changed3 в аварийном сигнале.";
        choice age-spec {
          description
            "Фильтр по дате и времени (возрасту).";
          case seconds {
            leaf seconds {
              type uint16;
              description
                "Возраст в секундах.";
            }
          }
          case minutes {
            leaf minutes {
              type uint16;
              description
                "Возраст в минутах.";
            }
          }
          case hours {
            leaf hours {
              type uint16;
              description
                "Возраст в часах.";
            }
          }
          case days {
            leaf days {
              type uint16;
              description
                "Возраст в днях.";
            }
          }
          case weeks {
            leaf weeks {
              type uint16;
              description
                "Возраст в неделях.";
            }
          }
        }
      }
      container severity {
        presence "Фильтр важности";
        choice sev-spec {
          description
            "Фильтр по уровню важности.";
          leaf below {
            type severity;
            description
              "Уровень важности меньше этого значения.";
          }
          leaf is {
            type severity;
            description
              "Уровень важности равен этому значению.";
          }
          leaf above {
            type severity;
            description
              "Уровень важности больше этого значения.";
          }
        }
        description
          "Фильтр на основе уровня важности.";
      }
      container operator-state-filter {
        if-feature "operator-actions";
        presence "Фильтр статуса у оператора";
        leaf state {
          type operator-state;
          description
            "Фильтр по состоянию у оператора.";
        }
        leaf user {
          type string;
          description
            "Фильтр по оператору.";
        }
        description
          "Фильтр по состоянию у оператора.";
      }
    }

    /*
     * Дерево данных /alarms 
     */

    container alarms {
      description
        "Контейнер верхнего уровня для модуля.";
      container control {
        description
          "Конфигурация управления поведением сигналов тревоги.";
        leaf max-alarm-status-changes {
          type union {
            type uint16;
            type enumeration {
              enum infinite {
                description
                  "Записи status-change собираются бесконечно.";
              }
            }
          }
          default "32";
          description
            "Записи status-change хранятся в кольцевых списках по 
             сигналам. Когда число записей превосходит это значение,
             самая старая запись о смене состояния автоматически
             удаляется. Если задано значение infinite, записи
             status-change накапливаются без ограничений.";
        }
        leaf notify-status-changes {
          type enumeration {
            enum all-state-changes {
              description
                "Передавать уведомления для любой смены состояния.";
            }
            enum raise-and-clear {
              description
                "Передавать уведомления только при активации, очистке и
                 реактивации. Уведомления о смене уровня важности и
                 alarm-text не передаются.";
            }
            enum severity-level {
              description
                "Передавать уведомления только при пересечении 
                 alarm-state уровня, заданного в notify-severity-level.
                 Уведомления об очистке передаются всегда.";
            }
          }
          must '. != "severity-level" or ../notify-severity-level' {
            description
              "При указании severity-level в notify-status-changes 
               должно быть задано значение для notify-severity-level.";
          }
          default "all-state-changes";
          description
            "Этот лист управляет передачей уведомлений при обновлении
             статуса сигнала тревоги. Возможны три варианта
             1.  Уведомления передаются для всех обновлений, смены
                 уровня важности и alarm-text.
             2.  Уведомления передаются только при активации и очистке 
                 сигнала.
             3.  Уведомления передаются лишь при достижении и превышении
                 заданного уровня важности. Уведомления об очистке
                 передаются всегда. Уведомления также передаются, если 
                 уровень важности становится меньше заданного порога.

             Предположим, например, что для вариант 3 задан уровень
             major и сигнал меняется, как показано ниже

             [(Time, severity, clear)]:
             [(T1, major, -), (T2, minor, -), (T3, warning, -),
              (T4, minor, -), (T5, major, -), (T6, critical, -),
              (T7, major.  -), (T8, major, clear)]

             Уведомления будут передаваться в моменты 
             T1, T2, T5, T6, T7, T8.";
        }
        leaf notify-severity-level {
          when '../notify-status-changes = "severity-level"';
          type severity;
          description
            "Уведомления передаются лишь при пересечении alarm-state 
             заданного уровня. Сведения об очистке передаются всегда.";
        }
        container alarm-shelving {
          if-feature "alarm-shelving";
          description
            "Список alarm-shelving/shelf служит для блокировки 
             (экранирования) сигналов тревоги. Условия блокировки
             объединяются операцией И (AND). Применяется первая 
             соответствующая блокировка и сигналы блокируются лишь для
             неё. Совпадающие сигналы ДОЛЖНЫ появляться в списке 
             /alarms/shelved-alarms/shelved-alarm, а несовпадающие
             ДОЛЖНЫ быть в списке /alarms/alarm-list/alarm. Сервер не
             передаёт уведомлений для заблокированных сигналов.

             Сервер ДОЛЖЕН поддерживать статус (например, смену уровня)
             для заблокированных сигналов.

             Сигналам, соответствующим критерию нужно иметь статус
             shelved у оператора. При удалении конфигурации блокировки
             серверу нужно установить у оператора статус un-shelved.";
          list shelf {
            key "name";
            ordered-by user;
            leaf name {
              type string;
              description
                "Произвольное имя для блокировки сигнала тревоги.";
            }
            description
              "Каждая запись задаёт критерий для блокировки сигналов.
               Критерии объединяются операцией И (AND). Если критерии не
               заданы, блокируются все сигналы.";
            leaf-list resource {
              type resource-match;
              description
                "Блокировать сигналы для соответствующих ресурсов.";
            }
            list alarm-type {
              key "alarm-type-id alarm-type-qualifier-match";
              description
                "Любой сигнал, соответствующий комбинации критериев
                 alarm-type-id и alarm-type-qualifier-match ДОЛЖЕН
                 соответствовать.";
              leaf alarm-type-id {
                type alarm-type-id;
                description
                  "Блокировать все сигналы с alarm-type-id совпадающим с
                   этим идентификатором или производным от него.";
              }
              leaf alarm-type-qualifier-match {
                type string;
                description
                  "регулярное выражение XML Schema для сопоставления с
                   классификаторам типа сигнала тревоги. Блокируются все
                   сигналы, классификатор которых соответствует.";
                reference
                  "XML Schema Part 2: Datatypes Second Edition,
                     World Wide Web Consortium Recommendation
                     REC-xmlschema-2-20041028";
              }
            }
            leaf description {
              type string;
              description
                "Необязательное текстовое описание блокировки, в котором
                 следует указывать причины блокировки сигналов.";
            }
          }
        }
      }
      container alarm-inventory {
        config false;
        description
          "Список alarm-inventory/alarm-type содержит все возможные типы
           аварийных сигналов для системы.

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

           Опись сигналов ДОЛЖНА обновляться системой при каждом 
           возможном появлении нового сигнала. Это может быть при 
           установке новых программных модулей или плат. При изменении 
           описи передаётся уведомление alarm-inventory-changed.";
        list alarm-type {
          key "alarm-type-id alarm-type-qualifier";
          description
            "Записи списка указывают возможные сигналы тревоги.";
          leaf alarm-type-id {
            type alarm-type-id;
            description
              "Статический идентификатор типа для этого сигнала.";
          }
          leaf alarm-type-qualifier {
            type alarm-type-qualifier;
            description
              "Необязательный динамический идентификатор типа сигнала.";
          }
          leaf-list resource {
            type resource-match;
            description
              "Указывает, к каким ресурсам применим сигнал (опция).";
          }
          leaf will-clear {
            type boolean;
            mandatory true;
            description
              "Этот лист говорит оператору, будет ли очищен сигнал при 
               выполнении верных корректирующих действий. Реализациям
               СЛЕДУЕТ стремиться к обнаружению статуса очистки для всех
               типов аварийных сигналов.

               При значении true оператор может наблюдать сигнал, пока
               тот не будет сброшен после корректировочных действий.

               При значении false оператор должен проверить, что сигнал
               больше не активен, с помощью иного механизма. Сигналы 
               могут не очищаться из-за отсутствия соответствующего 
               инструмента или логического статуса очистки.";
          }
          leaf-list severity-level {
            type severity;
            description
              "Указывает возможные уровни важности для сигнала тревоги.
               Следует отметить, что clear не относится к важности. В
               общем случае уровень важности следует задавать
               инструментально на основе динамического состояния, а не
               указывать статически, чтобы уровень важности динамически
               соответствовал состоянию и контексту. Однако тип сигнала
               должен иметь набор возможных уровней важности, который 
               следует указывать здесь.";
          }
          leaf description {
            type string;
            mandatory true;
            description
              "Описание возможного сигнала тревоги, в которое СЛЕДУЕТ
               включать сведения о возможных первопричинах и действиях
               по исправлению.";
          }
        }
      }
      container summary {
        if-feature "alarm-summary";
        config false;
        description
          "Контейнер для сводки по множеству сигналов.";
        list alarm-summary {
          key "severity";
          description
            "Глобальная сводка сигналов тревоги в системе. 
             Заблокированные сигналы в сводку не включаются.";
          leaf severity {
            type severity;
            description
              "Сводка аварийных сигналов с этим уровнем важности.";
          }
          leaf total {
            type yang:gauge32;
            description
              "Общее число сигналов с этим уровнем важности.";
          }
          leaf not-cleared {
            type yang:gauge32;
            description
              "Общее число не очищенных сигналов с этим уровнем.";
          }
          leaf cleared {
            type yang:gauge32;
            description
              "Число очищенных сигналов с этим уровнем важности.";
          }
          leaf cleared-not-closed {
            if-feature "operator-actions";
            type yang:gauge32;
            description
              "Число сигналов с этим уровнем важности, которые очищены,
               но не закрыты.";
          }
          leaf cleared-closed {
            if-feature "operator-actions";
            type yang:gauge32;
            description
              "Число сигналов с этим уровнем важности, которые очищены 
               и закрыты.";
          }
          leaf not-cleared-closed {
            if-feature "operator-actions";
            type yang:gauge32;
            description
              "Число сигналов с этим уровнем важности, которые не 
               очищены, но закрыты.";
          }
          leaf not-cleared-not-closed {
            if-feature "operator-actions";
            type yang:gauge32;
            description
              "Число сигналов с этим уровнем важности, которые не 
               очищены и не закрыты.";
          }
        }
        leaf shelves-active {
          if-feature "alarm-shelving";
          type empty;
          description
            "Подсказка оператору о активной блокировке сигналов тревоги.
             Этот лист ДОЛЖЕН существовать, если
             /alarms/shelved-alarms/number-of-shelved-alarms > 0.";
        }
      }
      container alarm-list {
        config false;
        description
          "Аварийные сигналы в системе.";
        leaf number-of-alarms {
          type yang:gauge32;
          description
            "Общее число аварийных сигналов в системе, т. е. число 
             записей в списке сигналов тревоги.";
        }
        leaf last-changed {
          type yang:date-and-time;
          description
            "Метка времени последнего изменения списка сигналов тревоги.
             Это значение может применяться для управления процессом
             ресинхронизации аварийных сигналов.";
        }
        list alarm {
          key "resource alarm-type-id alarm-type-qualifier";
          description
            "Список сигналов тревоги. Каждая записи списка содержит один
             сигнал для данного типа и ресурса. Сигнал может быть
             обновлён базовым ресурсом или пользователем. Ресурс 
             поддерживает листья is-cleared, last-change, 
             perceived-severity, alarm-text. Оператор может менять 
             operator-state и operator-text.

             Запись появляется в списке при первом возникновении сигнала
             этого типа для данного ресурса. При очистке сигнала запись
             из списка не удаляется. Статус очистки представляется 
             логическим флагом.

             Записи для сигналов удаляются путём явной операции очистки
             (purge). Например, можно удалить все очищенные и закрытые
             сигналы у оператора, которые старше 24 часов. Если статус
             связанного с сигналом ресурса изменится после очистки 
             (purge), сигнал снова появится в списке.

             Системы могут удалять сигналы тревоги на основе локально 
             заданных правил, но это выходит за рамки модуля.";
          uses common-alarm-parameters;
          leaf time-created {
            type yang:date-and-time;
            mandatory true;
            description
              "Метка времени создания записи для сигнала. Дальнейшие
               изменения этого сигнала не меняют значения метки и 
               отражаются в листе last-changed.";
          }
          uses resource-alarm-parameters;
          list operator-state-change {
            if-feature "operator-actions";
            key "time";
            description
              "Список, применяемый операторами для указания участия
               человека, связанного с аварийным сигналом. Например, 
               оператор может, увидев сигнал, добавить в этот список
               подтверждение.";
            uses operator-parameters;
          }
          action set-operator-state {
            if-feature "operator-actions";
            description
              "Средство для оператора указать степень вмешательства
               человека в сигнал тревоги.";
            input {
              leaf state {
                type writable-operator-state;
                mandatory true;
                description
                  "Состояние у этого оператора.";
              }
              leaf text {
                type string;
                description
                  "Дополнительная текстовая информация.";
              }
            }
          }
          notification operator-action {
            if-feature "operator-actions";
            description
              "Указывает, что оператор отреагировал на сигнал тревоги.";
            uses operator-parameters;
          }
        }
        action purge-alarms {
          description
            "Запрашивает у сервера удаление из списка сигналов, 
             соответствующих заданным критериям. Обычно это служит для
             удаления закрытых сигналов старше заданного времени.

             На выходе возвращается число удалённых сигналов.";
          input {
            uses filter-input;
          }
          output {
            leaf purged-alarms {
              type uint32;
              description
                "Число удалённых сигналов.";
            }
          }
        }
        action compress-alarms {
          if-feature "alarm-history";
          description
            "Запрашивает у сервера сжатие записей в списке сигналов 
             путём удаления всех соответствующих сигналов, кроме
             последней записи status-change. Заданные на входе условия
             объединяются операцией И (AND). Если условия не заданы,
             сжимаются все аварийные сигналы.";
          input {
            leaf resource {
              type resource-match;
              description
                "Сжимать сигналы, соответствующие этому ресурсу.";
            }
            leaf alarm-type-id {
              type leafref {
                path "/alarms/alarm-list/alarm/alarm-type-id";
                require-instance false;
              }
              description
                "Сжимать сигналы с этим alarm-type-id.";
            }
            leaf alarm-type-qualifier {
              type leafref {
                path "/alarms/alarm-list/alarm/alarm-type-qualifier";
                require-instance false;
              }
              description
                "Сжимать сигналы с этим alarm-type-qualifier.";
            }
          }
          output {
            leaf compressed-alarms {
              type uint32;
              description
                "Число сжатых записей сигналов тревоги.";
            }
          }
        }
      }
      container shelved-alarms {
        if-feature "alarm-shelving";
        config false;
        description
          "Заблокированные сигналы. Это сигналы, соответствующие
           критериям из /alarms/control/alarm-shelving. По этому списку
           не передаётся никаких уведомлений. Список включает сигналы,
           сочтённые неважными для оператора. Эти сигналы имеют 
           значение operator-state shelved, которое нельзя изменить.";
        leaf number-of-shelved-alarms {
          type yang:gauge32;
          description
            "Общее число текущих заблокированных сигналов тревоги, т. е. 
             записей в списке.";
        }
        leaf shelved-alarms-last-changed {
          type yang:date-and-time;
          description
            "Временная метка последнего изменения заблокированного
             сигнала. Значение может применяться менеджером для 
             процедуры ресинхронизации.";
        }
        list shelved-alarm {
          key "resource alarm-type-id alarm-type-qualifier";
          description
            "Список заблокированных сигналов. Эти сигналы может 
             обновлять лишь базовый ресурс, но не оператор.";
          uses common-alarm-parameters;
          leaf shelf-name {
            type leafref {
              path "/alarms/control/alarm-shelving/shelf/name";
              require-instance false;
            }
            description
              "Время блокировки.";
          }
          uses resource-alarm-parameters;
          list operator-state-change {
            if-feature "operator-actions";
            key "time";
            description
              "Список, применяемый операторами для указания участия
               человека, связанного с аварийным сигналом. Для
               заблокированных сигналов система устанавливает статус
               shelved.";
            uses operator-parameters;
          }
        }
        action purge-shelved-alarms {
          description
            "Запрашивает у сервера удаление заблокированных сигналов, 
             соответствующих заданным критериям. Из списка 
             заблокированных имеет смысл удалять сигналы, которые совсем
             не имеют смысла.
             На выходе возвращается число удалённых сигналов.";
          input {
            uses filter-input;
          }
          output {
            leaf purged-alarms {
              type uint32;
              description
                "Число очищенных (purge) сигналов тревоги.";
            }
          }
        }
        action compress-shelved-alarms {
          if-feature "alarm-history";
          description
            "Запрашивает у сервера сжатие записей в shelved-alarm
             путём удаления всех соответствующих сигналов, кроме
             последней записи status-change. Заданные на входе условия
             объединяются операцией И (AND). Если условия не заданы,
             сжимаются все аварийные сигналы в списке.";
          input {
            leaf resource {
              type leafref {
                path "/alarms/shelved-alarms/shelved-alarm/resource";
                require-instance false;
              }
              description
                "Сжимать сигналы от этого ресурса.";
            }
            leaf alarm-type-id {
              type leafref {
                path "/alarms/shelved-alarms/shelved-alarm"
                   + "/alarm-type-id";
                require-instance false;
              }
              description
                "Сжимать сигналы с этим alarm-type-id.";
            }
            leaf alarm-type-qualifier {
              type leafref {
                path "/alarms/shelved-alarms/shelved-alarm"
                   + "/alarm-type-qualifier";
                require-instance false;
              }
              description
                "Сжимать сигналы с этим alarm-type-qualifier.";
            }
          }
          output {
            leaf compressed-alarms {
              type uint32;
              description
                "Число сжатых записей сигналов тревоги.";
            }
          }
        }
      }
      list alarm-profile {
        if-feature "alarm-profile";
        key "alarm-type-id alarm-type-qualifier-match resource";
        ordered-by user;
        description
          "Задаёт дополнительные сведения или конфигурацию для каждого
           типа аварийных сигналов. Этот модуль поддерживает для клиента
           механизм переопределения заданных системой уровень важности
           сигналов. Список alarm-profile полезен также в качестве точек
           дополнения к конкретным типам сигналов.";
        leaf alarm-type-id {
          type alarm-type-id;
          description
            "Идентификатор типа сигнала для сопоставления.";
        }
        leaf alarm-type-qualifier-match {
          type string;
          description
            "Регулярное выражение XML Schema для сопоставления с 
             классификатором типа аварийного сигнала.";
          reference
            "XML Schema Part 2: Datatypes Second Edition,
               World Wide Web Consortium Recommendation
               REC-xmlschema-2-20041028";
        }
        leaf resource {
          type resource-match;
          description
            "Задаёт сопоставляемый ресурс.";
        }
        leaf description {
          type string;
          mandatory true;
          description
            "Описание профиля сигналов тревоги.";
        }
        container alarm-severity-assignment-profile {
          if-feature "severity-assignment";
          description
            "Клиент может переопределить системный уровень важности.";
          reference
            "ITU-T Recommendation M.3100:
               Generic network information model
             ITU-T Recommendation M.3160:
               Generic, protocol-neutral management information model";
          leaf-list severity-level {
            type severity;
            ordered-by user;
            description
              "Задаёт настроенные уровни важности для соответствующего
               сигнала тревоги. Если у сигнала несколько уровней, их 
               нужно указывать в порядке роста важности. Функция
               M3100/M3160 ASAP допускает лишь взаимнооднозначное
               соответствие между типом и важностью, но модуль YANG 
               поддерживает сигналы с учётом состояния, поэтому нужно
               разрешать несколько уровней важности для сигнала.

               Предположим сигнал о сильной загрузке с двумя порогами 
               для системных уровней важности threshold1 = warning
               и threshold2 = minor. Установка в этом leaf-list пары
               (minor, major) будет задавать уровни 
               threshold1 = minor и threshold2 = major";
          }
        }
      }
    }

    /*
     * Уведомления
     */

    notification alarm-notification {
      description
        "Служит для информирования о смене статуса сигнала. Одно 
         уведомление применяется для вновь возникшего и сброшенного
         сигнала, а также при изменении текста или важности 
         имеющегося сигнала.";
      uses common-alarm-parameters;
      uses alarm-state-change-parameters;
    }

    notification alarm-inventory-changed {
      description
        "Служит для информирования об изменении списка возможных
         сигналов тревоги. Это может случиться, например, при установке 
         нового программного модуля или платы.";
    }
  }
  <CODE ENDS>

7. Модуль сопоставления с X.733

Многие системы аварийных сигналов основаны на стандартах X.733 [X.733] и X.736 [X.736]. Модель ietf-alarms-x733 дополняет опись сигналов тревоги, список сигналов и уведомления о них параметрами X.733 и X.736. Модуль также поддерживает функцию, с помощью которой можно настроить сопоставления типов сигналов тревоги с параметрами X.733 event-type и probable-cause. Это может потребоваться, если принятое в системе по умолчанию сопоставления будет конфиликтовать с другими системами управления или будет сочтено некорректным.

Отметим, что термин ресурс (resource) в этом документе соответствует термину ITU managed object (управляемый объект).

Модуль YANG ссылается на [RFC6991], [X.721], [X.733] и [X.736].

   <CODE BEGINS> file "ietf-alarms-x733@2019-09-11.yang"
   module ietf-alarms-x733 {
     yang-version 1.1;
     namespace "urn:ietf:params:xml:ns:yang:ietf-alarms-x733";
     prefix x733;

     import ietf-alarms {
       prefix al;
     }
     import ietf-yang-types {
       prefix yang;
       reference
         "RFC 6991: Common YANG Data Types";
     }

     organization
       "IETF CCAMP Working Group";

     contact
       "WG Web:   <https://trac.ietf.org/trac/ccamp> 
        WG List:  <mailto:ccamp@ietf.org> 

        Editor:   Stefan Vallin
                  <mailto:stefan@wallan.se> 

        Editor:   Martin Bjorklund
                  <mailto:mbj@tail-f.com>"; 
     description
       "Этот модуль дополняет ietf-alarms параметрами сигналов X.733 для
        указанных ниже структур, указывая тип и возможную причину X.733.
         1) alarms/alarm-inventory - все возможные типы сигналов тревоги
         2) alarms/alarm-list - каждый сигнал тревоги в системе
         3) alarm-notification - уведомления о смене alarm-state
         4) alarms/shelved-alarms

        Модуль позволяет системам управления аварийными сигналами
        настраивать отображение ключей сигналов ietf-alarms на пары ITU
        (event-type, probable-cause). Отображение не включает значение
        соответствующей проблемы, специфичное для X.733. Рекомендуется
        применять лист alarm-type-qualifier, служащий для этого.

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

        Ключевые слова ДОЛЖНО, НЕДОПУСТИМО, ТРЕБУЕТСЯ, НУЖНО, НЕ НУЖНО, 
        СЛЕДУЕТ, НЕ СЛЕДУЕТ, РЕКОМЕНДУЕТСЯ, НЕ РЕКОМЕНДУЕТСЯ, МОЖНО,
        НЕОБЯЗАТЕЛЬНО в этом документе трактуются в соответствии с 
        BCP 14 (RFC 2119) (RFC 8174) тогда и только тогда, когда они
        указаны заглавными буквами, как показано здесь.

        Авторские права (Copyright (c) 2019) принадлежат IETF Trust и
        лицам, указанным как авторы. Все права защищены.

        Распространение и применение модуля в исходной или двоичной 
        форме с изменениями или без таковых разрешено в соответствии с
        лицензией Simplified BSD License, изложенной в параграфе 4.c
        IETF Trust's Legal Provisions Relating to IETF Documents
        (https://trustee.ietf.org/license-info). 

        Эта версия модуля YANG является частью RFC 8632, где правовые
        аспекты приведены более полно.";
     reference
       "ITU-T Recommendation X.733: Information Technology
          - Open Systems Interconnection
          - System Management: Alarm Reporting Function";

     revision 2019-09-11 {
       description
         "Исходный выпуск.";
       reference
         "RFC 8632: A YANG Data Model for Alarm Management";
     }

     /*
      * Свойства (функции)
      */

     feature configure-x733-mapping {
       description
         "Система поддерживает настраиваемое отображение alarm-type  
          из ietf-alarms на X733 event-type и probable-cause.";
     }

     /*
      * Определения типов
      */

     typedef event-type {
       type enumeration {
         enum other {
           value 1;
           description
             "Ничего из перечисленного ниже.";
         }
         enum communications-alarm {
           value 2;
           description
             "Сигнал, связанный в основном с процедурами и/или 
              процессами, требуемыми для переноса информации от
              одной точки к другой.";
         }
         enum quality-of-service-alarm {
           value 3;
           description
             "Сигнал, связанный в основном с отказом со снижением 
              качества обслуживания.";
         }
         enum processing-error-alarm {
           value 4;
           description
             "Сигнал, связанный в основном с отказом программы или
              обработки.";
         }
         enum equipment-alarm {
           value 5;
           description
             "Сигнал, связанный в основном с отказом оборудования.";
         }
         enum environmental-alarm {
           value 6;
           description
             "Сигнал, связанный в основном с условием, относящимся к
              шасси, где размещено оборудование.";
         }
         enum integrity-violation {
           value 7;
           description
             "Индикация возможного неправомерного изменение, вставки или
              удаления информации.";
         }
         enum operational-violation {
           value 8;
           description
             "Указание невозможности предоставления запрошенной услуги
              из-за недоступности, неисправности или некорректного
              вызова службы.";
         }
         enum physical-violation {
           value 9;
           description
             "Указывает нарушение физического ресурса способом, 
              предполагающим атаку.";
         }
         enum security-service-or-mechanism-violation {
           value 10;
           description
             "Указывает обнаружение атаки службой или механизмом
              безопасности.";
         }
         enum time-domain-violation {
           value 11;
           description
             "Событие произошло в неожиданный или запрещённый момент.";
         }
       }
       description
         "Типы событий, заданные в X.733 и X.736.";
       reference
         "ITU-T Recommendation X.733: Information Technology
            - Open Systems Interconnection
            - System Management: Alarm Reporting Function
          ITU-T Recommendation X.736: Information Technology
            - Open Systems Interconnection
            - System Management: Security Alarm Reporting Function";
     }

     typedef trend {
       type enumeration {
         enum less-severe {
           description
             "Имеется хотя бы один остающийся сигнал тревоги с важностью
              выше (более важный), чем текущий аварийный сигнал.";
         }
         enum no-change {
           description
             "Воспринимаемый уровень важности текущего сигнала совпадает
              с высшим (наиболее важным) из остающихся сигналов.";
         }
         enum more-severe {
           description
             "Воспринимаемый уровень важности текущего сигнала выше чем
              указанный в любом из остающихся сигналов тревоги.";
         }
       }
       description
         "Описывает тенденцию уровня важности сигналов связанного с 
          аварией ресурса.";
       reference
         "ITU-T Recommendation X.721: Information Technology
             - Open Systems Interconnection
             - Structure of management information:
               Definition of management information
               Module Attribute-ASN1Module";
     }

     typedef value-type {
       type union {
         type int64;
         type uint64;
         type decimal64 {
           fraction-digits 2;
         }
       }
       description
         "Общий тип объединения, соответствующий выбору ITU 
          целого или действительного числа.";
     }

     /*
      * Группировки
      */

     grouping x733-alarm-parameters {
       description
         "Базовые параметры X.733 для аварийных сигналов.";
       leaf event-type {
         type event-type;
         description
           "Тип события X.733/X.736 для этого сигнала.";
       }
       leaf probable-cause {
         type uint32;
         description
           "Возможная причина X.733 для этого сигнала.";
       }
       leaf probable-cause-string {
         type string;
         description
           "Понятная пользователю строка, соответствующая целочисленному
            значению возможной причины. Строке СЛЕДУЕТ соответствовать
            перечислению X.733, например, значение 27 - это
            localNodeTransmissionError.";
       }
       container threshold-information {
         description
           "Этот параметр нужно указывать, когда сигнал тревоги является
            результатом пересечения порога. ";
         leaf triggered-threshold {
           type string;
           description
             "Идентификатор порога, вызвавшего уведомление.";
         }
         leaf observed-value {
           type value-type;
           description
             "Значение датчика или счётчика, перешедшее порог. Это может
              отличаться от порога, если датчик может меняться, 
              например, только на дискретное значение.";
         }
         choice threshold-level {
           description
             "В случае датчика уровень порога задаёт пару пороговых
              значений - первое указывает сам порог, второе - 
              гистерезис. Для счётчика указывается только пороговое
              значение.";
           case up {
             leaf up-high {
               type value-type;
               description
                 "Порог повышения для сигнала тревоги.";
             }
             leaf up-low {
               type value-type;
               description
                 "Порог снижения для очистки сигнала тревоги. Это 
                  является гистерезисом для датчиков.";
             }
           }
           case down {
             leaf down-low {
               type value-type;
               description
                 "Порог снижения для сигнала тревоги.";
             }
             leaf down-high {
               type value-type;
               description
                 "Порог повышения для очистки сигнала тревоги. Это 
                 является гистерезисом для датчиков.";
             }
           }
         }
         leaf arm-time {
           type yang:date-and-time;
           description
             "Для порога датчика это время последнего перехода через 
              порог, время после предыдущего пересечения порога, когда
              значение гистерезиса для порога было превышено, разрешая
              генерацию уведомления для нового перехода через порог.
              Для порога счётчика это время последнего перехода через
              порог или время инициализации сбрасываемого счётчика.";
         }
       }
       list monitored-attributes {
         uses attribute;
         key "id";
         description
           "Необязательный параметр, который определяет один или
            несколько атрибутов ресурса и их значения в момент сигнала";
       }
       leaf-list proposed-repair-actions {
         type string;
         description
           "Необязательный параметр, который применяется, если причина
            сигнала известна и система может предложить одно или
            несколько решений (таких, как включение резервного
            оборудования, повтор действия или замена среды).";
       }
       leaf trend-indication {
         type trend;
         description
           "Задаёт текущую тенденцию уровня важности сигналов для
            ресурса. При наличии листа он указывает наличие одного
            или нескольких сигналов (остающиеся сигналы), которые не
            были очищены и относятся к тому же ресурсу, сто и этот
            (текущий) сигнал. Возможные значения включают:
              more-severe - воспринимаемая важность текущего сигнала
                выше, чем у любого из остающихся;
              no-change - воспринимаемая важность текущего сигнала
                совпадает с наивысшей среди остающихся сигналов;
              less-severe - среди остающихся имеется хотя бы один
                сигнал с важностью выше, чем у текущего сигнала.";
       }
       leaf backedup-status {
         type boolean;
         description
           "Необязательный лист, указывающий, резервируется ли ресурс,
            с которым связан сигнал, что позволяет узнать, были ли 
            нарушены условия предоставления услуг клиентам. Применение
            этого поля вместе с perceived-severity обеспечивает сведения
            для независимого определения серьёзности сигнала тревоги и
            способности системы в целом продолжать предоставление услуг.
            Если лист имеет значение true, это указывает, что объект,
            создавший сигнал тревоги, резервируется, а значение 
            false говорит об отсутствии резервирования.";
       }
       leaf backup-object {
         type al:resource;
         description
           "Этот лист НУЖНО включать при наличии backedup-status true. 
            Лист указывает экземпляр управляемого объекта, резервирующий
            управляемый объект, к которому относится уведомление. Лист
            полезен, например, при резервировании объекта иным объектом
            из пула, выделяемым на подмену динамически.";
       }
       list additional-information {
         key "identifier";
         description
           "Позволяет включать в сигнал тревоги дополнительные сведения.
            Это серия структур данных, каждая из которых содержит три
            элемента: идентификатор, индикатор значимости и сведения
            о проблеме.";
         leaf identifier {
           type string;
           description
             "Тип данных в информационном параметре.";
         }
         leaf significant {
           type boolean;
           description
             "Устанавливается true, если принимающая система должна быть
              способная разобрать информационный параметр события, чтобы
              полностью понять отчёт.";
         }
         leaf information {
           type string;
           description
             "Дополнительные сведения о сигнале тревоги.";
         }
       }
       leaf security-alarm-detector {
         type al:resource;
         description
           "Указывает датчик сигнала тревоги.";
       }
       leaf service-user {
         type al:resource;
         description
           "Указывает пользователя службы, чей запрос вызвал сигнал
            тревоги, связанный с безопасностью.";
       }
       leaf service-provider {
         type al:resource;
         description
           "Указывает предполагаемого поставщика услуги, вызвавшей
            сигнал тревоги, связанный с безопасностью.";
       }
       reference
         "ITU-T Recommendation X.733: Information Technology
            - Open Systems Interconnection
            - System Management: Alarm Reporting Function
          ITU-T Recommendation X.736: Information Technology
            - Open Systems Interconnection
            - System Management: Security Alarm Reporting Function";
     }

     grouping x733-alarm-definition-parameters {
       description
         "Базовые параметры X.733 для определений сигналов тревоги.
          Эта группировка служит для задания атрибутов сигналов,
          которые можно сопоставить с механизмом alarm-type в модуле
          ietf-alarms.";
       leaf event-type {
         type event-type;
         description
           "Тип сигнала тревоги для этого типа события X.733/X.736.";
       }
       leaf probable-cause {
         type uint32;
         description
           "Тип сигнала тревоги имеет возможной эту причину X.733.
            Модуль задаёт возможные причины целыми числами, а не
            перечислением. Это связано с тем, что основным 
            применением возможных причин являются управляющие 
            приложения, если они основаны на стандарте X.733. Однако в
            большинстве управляющий приложений имеются свои 
            перечисления причин и слияние перечислений из разных систем
            может вызывать конфликты. Используя настраиваемые значения
            uint32, система может работать с перечисляемыми значениями
            в управляющих приложениях.";
       }
       leaf probable-cause-string {
         type string;
         description
           "Строка с понятным пользователю указанием возможной причины";
       }
     }

     grouping attribute {
       description
         "Группировка для сопоставления базовой ссылки ITU с атрибутом";
       leaf id {
         type al:resource;
         description
           "Ресурс, представляющий атрибут.";
       }
       leaf value {
         type string;
         description
           "Значение представлено строкой, поскольку оно может быть
            любого типа.";
       }
       reference
         "ITU-T Recommendation X.721: Information Technology
             - Open Systems Interconnection
             - Structure of management information:
               Definition of management information
          Module Attribute-ASN1Module";
     }

     /*
      * Параметры X.733 для определений сигналов тревоги, сигналов
      * и уведомлений.
      */

     augment "/al:alarms/al:alarm-inventory/al:alarm-type" {
       description
         "Добавляет сведения отображения X.733 в сводку сигналов.";
       uses x733-alarm-definition-parameters;
     }

     /*
      * Добавляет настраиваемое отображение X.733.
      */

     augment "/al:alarms/al:control" {
       description
         "Добавляет возможности отображения X.733.";
       list x733-mapping {
         if-feature "configure-x733-mapping";
         key "alarm-type-id alarm-type-qualifier-match";
         description
           "Список, позволяющий приложению управления контролировать
            отображения X.733 лоя всех сигналов тревоги в системе. Любая
            запись списка позволяет менеджеру сигналов тревоги 
            переопределить отображение X.733 и в описи сигналов будет 
            указано финальное сопоставление.";
         leaf alarm-type-id {
           type al:alarm-type-id;
           description
             "Сопоставление типа сигнала с идентификатором типа.";
         }
         leaf alarm-type-qualifier-match {
           type string;
           description
             "регулярное выражение W3C, применяемое при сопоставлении 
              типа и классификатора сигнала с параметрами X.733.";
         }
         uses x733-alarm-definition-parameters;
       }
     }

     augment "/al:alarms/al:alarm-list/al:alarm" {
       description
         "Добавление информации X.733 для сигнала.";
       uses x733-alarm-parameters;
     }

     augment "/al:alarms/al:shelved-alarms/al:shelved-alarm" {
       description
         "Добавление информации X.733 для сигнала.";
       uses x733-alarm-parameters;
     }

     augment "/al:alarm-notification" {
       description
         "Добавление информации X.733 для уведомления о сигнале.";
       uses x733-alarm-parameters;
     }
   }
   <CODE ENDS>

8. Взаимодействие с IANA

Этот документ регистрирует два URIs в реестре IETF XML Registry в соответствии с [RFC3688].

       URI: urn:ietf:params:xml:ns:yang:ietf-alarms
       Registrant Contact: The IESG.
       XML: N/A; запрошенный URI является пространством имён XML.

       URI: urn:ietf:params:xml:ns:yang:ietf-alarms-x733
       Registrant Contact: The IESG.
       XML: запрошенный URI является пространством имён XML.

Документ регистрирует два модуля YANG в реестре YANG Module Names [RFC6020].

       name:        ietf-alarms
       namespace:   urn:ietf:params:xml:ns:yang:ietf-alarms
       prefix:      al
       reference:   RFC 8632

       name:        ietf-alarms-x733
       namespace:   urn:ietf:params:xml:ns:yang:ietf-alarms-x733
       prefix:      x733
       reference:   RFC 8632

9. Вопросы безопасности

Заданные в этом документе модули YANG определяют схему для данных, которые предназначены для доступа через сеть с помощью протоколов управления, таких как NETCONF [RFC6241] или RESTCONF [RFC8040]. Нижним уровнем NETCONF является защищённый сетевой транспорт с обязательной реализацией протокола SSH4 [RFC6242], а нижним уровнем RESTCONF — протокол HTTPS с обязательной реализацией TLS [RFC5246].

Модель контроля доступа NETCONF (Network Configuration Access Control Model или NACM) [RFC8341] позволяет разрешать доступ к заданному подмножеству доступных операций и содержимого NETCONF или RESTCONF лишь уполномоченным пользователям NETCONF или RESTCONF.

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

В этих модулях данных YANG имеется множество узлов, для которых возможна запись, создание и/или удаление (значение config true, которое устанавливается по умолчанию). Такие узлы могут считаться деликатными или уязвимыми в некоторых сетевых средах. Операции записи (например, edit-config) в такие узлы без подобающей защиты могут оказать негативное влияние на работу сети. Ниже перечислены узлы и ветви модуля ietf-alarms, которые могут быть уязвимы.

/alarms/control/notify-status-changes

Этот лист указывает, следует ли сигналу тревоги уведомлять о смене состояний системы. Несанкционированный доступ к листу может негативно влиять на рабочие процедуры, основанный на точных отчётах об изменении статуса сигналов тревоги.

/alarms/control/alarm-shelving/shelf

Этот список управляет блокировкой аварийных сигналов. Несанкционированный доступ может нарушить работу процедур управления сигналами тревоги.

/alarms/control/alarm-profile/alarm-severity-assignment-profile

Этот список управляет важностью сигналов тревоги. Несанкционированный доступ может позволить, например, снизить уровень важности сигнала, что может негативно повлиять на процессы слежения за сигналами.

Некоторые из операций RPC в этом модуле YANG могут быть чувствительны или уязвимы в той или иной сетевой среде. Важно контролировать доступ к таким операциям. Ниже указаны такие операции.

/alarms/alarm-list/purge-alarms

Это действие удаляет сигналы тревоги из списка. Несанкционированное применение действия может нарушить работу процедур управления сигналами, поскольку удалённый сигнал может быть важен для работы системы управления аварийными сигналами.

/alarms/alarm-list/alarm/set-operator-state

Это действие оператор может использовать для указания степени вмешательства человека по сигналу тревоги. Несанкционированное применение действия может приводить к игнорированию сигналов операторами.

10. Литература

10.1. Нормативные документы

[M.3100] International Telecommunication Union, «Generic network information model», ITU-T Recommendation M.3100, April 2005, <https://www.itu.int/rec/T-REC-M.3100-200504-I/en>.

[M.3160] International Telecommunication Union, «Generic, protocol-neutral management information model», ITU-T Recommendation M.3100, November 2008, <https://www.itu.int/rec/T-REC-M.3160-200811-I>.

[RFC2119] Bradner, S., «Key words for use in RFCs to Indicate Requirement Levels», BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, <https://www.rfc-editor.org/info/rfc2119>.

[RFC3688] Mealling, M., «The IETF XML Registry», BCP 81, RFC 3688, DOI 10.17487/RFC3688, January 2004, <https://www.rfc-editor.org/info/rfc3688>.

[RFC6020] Bjorklund, M., Ed., «YANG — A Data Modeling Language for the Network Configuration Protocol (NETCONF)», RFC 6020, DOI 10.17487/RFC6020, October 2010, <https://www.rfc-editor.org/info/rfc6020>.

[RFC6241] Enns, R., Ed., Bjorklund, M., Ed., Schoenwaelder, J., Ed., and A. Bierman, Ed., «Network Configuration Protocol (NETCONF)», RFC 6241, DOI 10.17487/RFC6241, June 2011, <https://www.rfc-editor.org/info/rfc6241>.

[RFC6242] Wasserman, M., «Using the NETCONF Protocol over Secure Shell (SSH)», RFC 6242, DOI 10.17487/RFC6242, June 2011, <https://www.rfc-editor.org/info/rfc6242>.

[RFC6991] Schoenwaelder, J., Ed., «Common YANG Data Types», RFC 6991, DOI 10.17487/RFC6991, July 2013, <https://www.rfc-editor.org/info/rfc6991>.

[RFC7950] Bjorklund, M., Ed., «The YANG 1.1 Data Modeling Language», RFC 7950, DOI 10.17487/RFC7950, August 2016, <https://www.rfc-editor.org/info/rfc7950>.

[RFC8040] Bierman, A., Bjorklund, M., and K. Watsen, «RESTCONF Protocol», RFC 8040, DOI 10.17487/RFC8040, January 2017, <https://www.rfc-editor.org/info/rfc8040>.

[RFC8174] Leiba, B., «Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words», BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017, <https://www.rfc-editor.org/info/rfc8174>.

[RFC8341] Bierman, A. and M. Bjorklund, «Network Configuration Access Control Model», STD 91, RFC 8341, DOI 10.17487/RFC8341, March 2018, <https://www.rfc-editor.org/info/rfc8341>.

[RFC8348] Bierman, A., Bjorklund, M., Dong, J., and D. Romascanu, «A YANG Data Model for Hardware Management», RFC 8348, DOI 10.17487/RFC8348, March 2018, <https://www.rfc-editor.org/info/rfc8348>.

[RFC8446] Rescorla, E., «The Transport Layer Security (TLS) Protocol Version 1.3», RFC 8446, DOI 10.17487/RFC8446, August 2018, <https://www.rfc-editor.org/info/rfc8446>.

[X.721] International Telecommunication Union, «Information technology — Open Systems Interconnection — Structure of management information: Definition of management information», ITU-T Recommendation X.721, February 1992, <https://www.itu.int/rec/T-REC-X.721-199202-I/en>.

[X.733] International Telecommunication Union, «Information technology — Open Systems Interconnection — Systems Management: Alarm reporting function», ITU-T Recommendation X.733, February 1992, <https://www.itu.int/rec/T-REC-X.733-199202-I/en>.

[XSD-TYPES] Malhotra, A. and P. Biron, «XML Schema Part 2: Datatypes Second Edition», World Wide Web Consortium Recommendation REC-xmlschema-2-20041028, October 2004, <http://www.w3.org/TR/2004/REC-xmlschema-2-20041028>.

10.2. Дополнительная литература

[ALARMIRP] 3GPP, «Telecommunication management; Fault Management; Part 2: Alarm Integration Reference Point (IRP): Information Service (IS)», 3GPP TS 32.111-2, March 2005, <http://www.3gpp.org/ftp/Specs/html-info/32111-2.htm>.

[ALARMSEM] Wallin, S., Leijon, V., Nordlander, J., and N. Bystedt, «The semantics of alarm definitions: enabling systematic reasoning about alarms», International Journal of Network Management, Volume 22, Issue 3, May 2012, <http://dx.doi.org/10.1002/nem.800>.

[EEMUA] «Alarm systems: a guide to design, management and procurement», EEMUA Publication No. 191, Engineering Equipment and Materials Users Association, Second Edition, 2007.

[G.7710] International Telecommunication Union, «SERIES G: TRANSMISSION SYSTEMS AND MEDIA, DIGITAL SYSTEMS AND NETWORKS — Data over Transport — Generic aspects — Transport network control aspects; Common equipment management function requirements», ITU-T Recommendation G.7710/Y.1701, Amendment 1, November 2012.

[ISA182] International Society of Automation, «Management of Alarm Systems for the Process Industries», ANSI/ISA — 18.2-2016, March 2016.

[RFC3877] Chisholm, S. and D. Romascanu, «Alarm Management Information Base (MIB)», RFC 3877, DOI 10.17487/RFC3877, September 2004, <https://www.rfc-editor.org/info/rfc3877>.

[RFC8340] Bjorklund, M. and L. Berger, Ed., «YANG Tree Diagrams», BCP 215, RFC 8340, DOI 10.17487/RFC8340, March 2018, <https://www.rfc-editor.org/info/rfc8340>.

[X.736] International Telecommunication Union, «Information technology — Open Systems Interconnection — Systems Management: Security alarm reporting function», ITU-T Recommendation X.736, January 1992, <https://www.itu.int/rec/T-REC-X.736-199201-I/en>.

[YANG-INSTANCE] Lengyel, B. and B. Claise, «YANG Instance Data File Format», Work in Progress5, draft-ietf-netmod-yang-instance-file-format-02, August 2019.

Приложение A. Примеры фирменных типов сигналов

В примере показано, как определить сигналы тревоги в фирменном модуле производителя. Здесь производитель xyz задаёт идентификаторы верхнего уровня по типам событий X.733.

   module example-xyz-alarms {
     namespace "urn:example:xyz-alarms";
     prefix xyz-al;

     import ietf-alarms {
       prefix al;
     }

     identity xyz-alarms {
       base al:alarm-type-id;
     }

     identity communications-alarm {
       base xyz-alarms;
     }
     identity quality-of-service-alarm {
       base xyz-alarms;
     }
     identity processing-error-alarm {
       base xyz-alarms;
     }
     identity equipment-alarm {
       base xyz-alarms;
     }
     identity environmental-alarm {
       base xyz-alarms;
     }

     // Коммуникационные сигналы тревоги
     identity link-alarm {
       base communications-alarm;
     }

     // Сигналы QoS
     identity high-jitter-alarm {
       base quality-of-service-alarm;
     }
   }

Приложение B. Пример сводки аварийных сигналов

Здесь показана опись аварийных сигналов. Один тип сигналов определён только идентификатором, другой настраивается динамически. В последнем случае цифровой вход подключён к датчику дыма, поэтому для alarm-type-qualifier выбран классификатор smoke-detector, а для alarm-type-id — environmental-alarm.

   <alarms xmlns="urn:ietf:params:xml:ns:yang:ietf-alarms"
           xmlns:xyz-al="urn:example:xyz-alarms"
           xmlns:dev="urn:example:device">
     <alarm-inventory>
       <alarm-type>
         <alarm-type-id>xyz-al:link-alarm</alarm-type-id>
         <alarm-type-qualifier/>
         <resource>
           /dev:interfaces/dev:interface
         </resource>
         <will-clear>true</will-clear>
         <description>
           Отказ канала, рабочее состояние down, административное - up.
         </description>
       </alarm-type>
       <alarm-type>
         <alarm-type-id>xyz-al:environmental-alarm</alarm-type-id>
         <alarm-type-qualifier>smoke-alarm</alarm-type-qualifier>
         <will-clear>true</will-clear>
         <description>
           Датчик дыма подключён к цифровому входу.
         </description>
       </alarm-type>
     </alarm-inventory>
   </alarms>

Приложение C. Пример списка сигналов тревоги

В этом примере показаны смена состояния сигнала тревоги [major, clear, major]. Оператор подтвердил сигнал.

   <alarms xmlns="urn:ietf:params:xml:ns:yang:ietf-alarms"
           xmlns:xyz-al="urn:example:xyz-alarms"
           xmlns:dev="urn:example:device">
     <alarm-list>
       <number-of-alarms>1</number-of-alarms>
       <last-changed>2018-04-08T08:39:50.00Z</last-changed>
       <alarm>
         <resource>
           /dev:interfaces/dev:interface[name='FastEthernet1/0']
         </resource>
         <alarm-type-id>xyz-al:link-alarm</alarm-type-id>
         <alarm-type-qualifier></alarm-type-qualifier>
         <time-created>2018-04-08T08:20:10.00Z</time-created>
         <is-cleared>false</is-cleared>
         <alt-resource>1.3.6.1.2.1.2.2.1.1.17</alt-resource>
         <last-raised>2018-04-08T08:39:40.00Z</last-raised>
         <last-changed>2018-04-08T08:39:50.00Z</last-changed>
         <perceived-severity>major</perceived-severity>
         <alarm-text>
           Рабочее состояние канала down, административное - up.
         </alarm-text>
         <status-change>
           <time>2018-04-08T08:39:40.00Z</time>
           <perceived-severity>major</perceived-severity>
           <alarm-text>
             Рабочее состояние канала down, административное - up.
           </alarm-text>
         </status-change>
         <status-change>
           <time>2018-04-08T08:30:00.00Z</time>
           <perceived-severity>cleared</perceived-severity>
           <alarm-text>
             Рабочее состояние канала up, административное - up.
           </alarm-text>
         </status-change>
         <status-change>
           <time>2018-04-08T08:20:10.00Z</time>
           <perceived-severity>major</perceived-severity>
           <alarm-text>
             Рабочее состояние канала up, административное - up.
           </alarm-text>
         </status-change>
         <operator-state-change>
           <time>2018-04-08T08:39:50.00Z</time>
           <state>ack</state>
           <operator>joe</operator>
           <text>Будет изучаться, квитанция TR764999</text>
         </operator-state-change>
       </alarm>
     </alarm-list>
   </alarms>

Приложение D. Пример блокировки аварийных сигналов

В примере показано, как блокировать сигналы тревоги. Здесь блокируются сигналы, связанные с детекторами дыма, поскольку они недавно установлены и тестируются. Заблокированы также все сигналы от интерфейса FastEthernet1/0.

   <alarms xmlns="urn:ietf:params:xml:ns:yang:ietf-alarms"
           xmlns:xyz-al="urn:example:xyz-alarms"
           xmlns:dev="urn:example:device">
     <control>
       <alarm-shelving>
         <shelf>
           <name>FE10</name>
           <resource>
             /dev:interfaces/dev:interface[name='FastEthernet1/0']
           </resource>
         </shelf>
         <shelf>
           <name>detectortest</name>
           <alarm-type>
             <alarm-type-id>
               xyz-al:environmental-alarm
             </alarm-type-id>
             <alarm-type-qualifier-match>
               smoke-alarm
             </alarm-type-qualifier-match>
           </alarm-type>
         </shelf>
       </alarm-shelving>
     </control>
   </alarms>

Приложение E. Пример отображения X.733

В примере показано, как сопоставить сигнал тревоги динамического типа (alarm-type-id=environmental-alarm, alarm-type-qualifier=smoke-alarm) с соответствующими параметрами X.733 event-type и probable-cause.

   <alarms xmlns="urn:ietf:params:xml:ns:yang:ietf-alarms"
           xmlns:xyz-al="urn:example:xyz-alarms">
     <control>
       <x733-mapping
          xmlns="urn:ietf:params:xml:ns:yang:ietf-alarms-x733">
         <alarm-type-id>xyz-al:environmental-alarm</alarm-type-id>
         <alarm-type-qualifier-match>
           smoke-alarm
         </alarm-type-qualifier-match>
         <event-type>quality-of-service-alarm</event-type>
         <probable-cause>777</probable-cause>
       </x733-mapping>
     </control>
   </alarms>

Приложение F. Связь с другими стандартами

В этом приложении кратко рассмотрена связь модели данных для сигналов тревоги с другими стандартами.

F.1. Определение сигналов тревоги

В таблице 1 приведены определения термина alarm (сигнал тревоги, аварийный сигнал ) в других стандартах.

Таблица 1. Определения термина Alarm в стандартах.

Стандарт

Определение

Комментарии

X.733 [X.733]

Ошибка. Отклонение системы от нормальной работы. Отказ. Физическая или алгоритмическая причина неисправности, проявляющейся как ошибка.
Сигнал тревоги. Уведомление в определённой этой функцией форме о конкретном событии. Сигнал тревоги не всегда представляет ошибку.

Определение сигнала тревоги в X.733 сосредоточено на уведомлении, а не на состоянии. X.733 определяет сигнал тревоги как отклонение от нормальных условий, не обязательно требующее корректировочных действий.

G.7710 [G.7710]

Сигналы тревоги — это индикация, автоматически подаваемая устройством при обнаружении отказа.

Определение G.7710 близко к исходному определению X.733.

Alarm MIB [RFC3877]

Сигнал тревоги — это сохраняющаяся индикация отказа. Ошибка — отклонение системы от нормальной работы.

В RFC 3877 сигнал тревоги определён как отклонение от нормальной работы. Модель данных YANG для сигналов тревоги добавляет требование корректировочных действий, что говорит о нежелательности, а не только об отклонении от нормальной работы. База MIB для сигналов тревоги похожа в этом смысле на модуль YANG и сосредоточена на длительном состоянии, а не на отдельных уведомлениях.

ISA [ISA182]

Сигнал тревоги — звуковая и/или визуальная индикация для оператора неисправности оборудования, отклонения процесса или аномальных условий, где требуется реагирование.

Стандарт ISA добавляет важное требование отклонения от нормального состояния, требующего реагирования.

EEMUA [EEMUA]

Сигнал тревоги — это событие, на которое оператор должен осознанно реагировать, отвечать и подтверждать (а не просто подтвердить и забыть).

Это основа определения сигнала тревоги в данном документе. Основное внимание уделено необходимости реального действия.

3GPP Alarm IRP [ALARMIRP]

3GPP v15 называет сигналом тревоги указание нежелательных условий для ресурса (например, канала, устройства), требующее действиия оператора. Подчёркивается ключевое требование, что оператора […] не следует информировать о нежелательных условиях, пока они не требуют действий.
3GPP v12 считает аварийным сигналом аномальное состояние объекта сети, которое классифицирует событие как отказ. Отказом считается отклонение системы от нормальной работы, которое может приводить к потере операционных возможностей […]

Последняя версия 3GPP Alarm IRP использует точно такое же определение сигнала тревоги, как и эта модель данных. Следует отметить, что в ранних версиях использовалось определение, не требующее действий оператора, и более широкое определение отклонения от нормальных условий. Ранняя версия также определяла сигнал тревоги как особый случай события.

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

F.2. Модель данных

Здесь описано, как модель данных YANG для сигналов тревоги связана с моделями из других стандартов. Отметим, что рассматриваются модели данных для интерфейсов аварийных сигналов, а не другие стандарты, такие как специфичные для SDO аварийные сигналы.

F.2.1. X.733

X.733 служит базой для нескольких моделей данных сигналов тревоги в течение лет. Отличия от модели данных YANG перечислены ниже.

X.733 представляет список аварийных сигналов как список уведомлений. Модель данных YANG определяет список сигналов тревоги как список текущих состояний сигналов, который создаётся по уведомлениям о смене статуса.

В X.733 для сигналов тревоги имеется уровень clear (очищен). В модели YANG clear не является уровнем важности, это отдельное состояние аварийного сигнала. Сигнал тревоги может иметь, например, состояния (major, cleared) и (minor, not cleared).

X.733 использует плоский глобально заданный список перечисляемых probable-cause для указания типа сигналов тревоги. Описанная здесь модель использует иерархическое отождествления YANG alarm-type. Это позволяет организациям определять свои типы аварийных сигналов, а также применять абстрактные типы сигналов тревоги, соответствующие базовым идентификаторам (3.2. Тип сигнала тревоги).

Модель данных YANG для сигналов тревоги не включает большинство атрибутов аварийных сигналов X.733, вместо этого они определяются в модуле дополнения [X.733], если требуется строгое соответствие X.733.

F.2.2. Alarm MIB (RFC 3877)

MIB в RFC 3877 использует другой подход — вместо задания конкретной модели данных для сигналов тревоги определена модель сопоставления имеющихся объектов, управляемых по SNMP, и уведомлений с состояниями сигналов тревоги и уведомлениями о сигналах. Это было необходимо, поскольку базы MIB уже были определены для управляемых объектов и уведомлений, указывающих сигналы тревоги, например, уведомления linkUp и linkDown в сочетании с ifAdminState и ifOperState. Поэтому RFC 3877 реально не сравнивается с модулем YANG в этом смысле.

Alarm MIB сопоставляет имеющиеся определения MIB с сигналами тревоги, такими как alarmModelTable. Преимущество этого состоит в том, что менеджер SNMP может в процессе работы считывать возможные типы сигналов тревоги. Это соответствует alarmInventory в модуле YANG.

F.2.3. 3GPP Alarm IRP

3GPP Alarm IRP является развитием X.733. Основные различия между модулем YANG и 3GPP указаны ниже.

3GPP сохраняет большинство атрибутов X.733, модуль YANG — нет.

В 3GPP введены перекрывающиеся и, возможно, конфликтующие ключи для сигналов тревоги alarmId и квартет (managed object, event type, probable cause, specific problem), см. пример 3 в Annex C [ALARMIRP]. В модели данных YANG ключ для идентификации экземпляра аварийного сигнала чётко определён тройкой (resource, alarm-type-id, alarm-type-qualifier), см. 3.4. Идентификация экземпляров аварийных сигналов.

Модуль YANG для сигналов тревоги чётко разделяет жизненный цикл сигнала в ресурсе (измерителе) и у оператора. 3GPP разрешает операторам устанавливать для уровня важности значение clear, что не разрешено в описанном здесь модуле. Вместо этого оператор закрывает сигнал, что не влияет на уровень важности.

F.2.4. G.7710

G.7710 отличается от упомянутых выше стандартов для аварийных сигналов, он не задаёт модели данных для информирования о сигналах тревоги. Стандарт определяет общие требования к функциям управления оборудованием и предназначен для транспортных сетей.

Требования G.7710 соответствуют функциям (feature) модуля YANG, как указано ниже.

Alarm Severity Assignment Profile (ASAP)

Профиль /alarms/alarm-profile/.

Alarm Reporting Control (ARC)

Блокировка сигналов /alarms/control/alarm-shelving/ и возможность контролировать уведомления о сигналах /alarms/control/notify-status-changes. Блокировка сигналов соответствует варианту отключения отчётов о сигналах тревоги для конкретного ресурса — состояние NALM (No ALarM) в M.3100.

Приложение G. Требования к применимости аварийных сигналов

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

Основные проблемы, связанные с аварийными сигналами, и их причины указаны в таблице 2. Эта сводка адаптирована для работы в сетях на основе стандартов ISA [ISA182] и EEMUA (Engineering Equipment Materials Users Association) [EEMUA].

Таблица 2. Проблемы и причины аварийных сигналов.

Проблема

Причина

Решение проблемы

Сигналы генерируются, но оператор игнорирует их.

Раздражающие сигналы (дребезжащие и мимолётные), неисправное оборудование, избыточные сигналы, некорректные настройки сигналов, нерационализированные сигналы, сигналы, представляющие скорей записи системного журнала, чем фактические аварии.

Строгое определение аварийных сигналов, требующих корректировочных действий. См. таблицу 3.

При наличии сигнала оператор не знает, как действовать.

Нечёткие процедуры реагирования на сигналы и нечётко определённые типы аварийных сигналов.

Опись аварийных сигналов со всеми типами сигналов и корректировочными действиями. См. таблицу 3.

Сигналов выдаётся слишком много даже при отсутствии реальных проблем.

Раздражающие сигналы, устаревшие сигналы и сигналы от оборудования, которое не эксплуатируется.

Определения и блокировка аварийных сигналов.

При возникновении отказа оператор получает очень много сигналов и не знает, какие из них важнее.

Некорректная приоритизация сигналов, отказ от использования расширенных методов (например, сигналов на основе состояний).

Модель основанных на состояниях аварийных сигналов и требования к частоте сигналов. См. таблицы 4 и 5.

С учётом этих проблем в EEMUA даны приведённые ниже определения «хороших» сигналов тревоги.

Таблица 3. Определение «хороших» сигналов.

Характеристика

Объяснение

Соответствие (релевантность)

Сигналы не являются ложными и малозначительными.

Уникальность

Сигналы не дублируют друг друга.

Своевременность

Не слишком поздно, чтобы можно было ещё что-то сделать.

Приоритизация

Указывается важность проблемы, с которой имеет дело оператор.

Понятность

Сообщение является чётким и простым для понимания.

Диагностика

Указывается проблема, которая возникла.

Консультативность

Указываются действия, которые нужно предпринять.

Сфокусированность

Привлекается внимание к наиболее важным вопросам.

Производителям следует рационализировать все сигналы тревоги в соответствии с таблицей 3. Другим важным требованием является частота уведомлений о сигналах тревоги. Производителям следует убедиться, что частота не превышает рекомендации EEMUA в таблице 4.

Таблица 4. Допустимая частота передачи аварийных сигналов в установившемся состоянии.

 

Долгосрочная частота сигналов в стабильном состоянии

Приемлемость

Более 1 в минуту

Скорей всего неприемлемо

Одно за 2 минуты

Скорей всего избыточно

Одно за 5 минут

Допустимо

Меньше одного за 10 минут

Скорей всего приемлемо

 

Таблица 5. Допустимые скорости аварийных сигналов в пиках.

Число аварийных сигналов, отображаемых за 10 минут после важной сетевой проблемы

Приемлемость

Более 100

Чрезмерно и скорей всего приведёт к отказу оператора от использования системы аварийной сигнализации.

20-100

Тяжело справиться.

Менее 10

Допустимо, но могут возникать сложности, если несколько сигналов тревоги требуют сложных действий оператора.

Значения в таблицах 4 и 5 указаны для суммы всех аварийных сигналов для сети, контролируемых с одной консоли. Таким образом, каждая отдельная система и NMS (Network Management System) вносит свой вклад.

Производителям следует при разработке интерфейса аварийных сигналов обеспечивать выполнение приведённых ниже правил.

  1. Рационализация сигналов тревоги в системе, чтобы каждый сигнал был необходимым, имел своё назначение и соответствовал основному правилу, требующему реакции оператора (Таблица 3).

  2. Проверка качества аварийных сигналов. Следует обсудить с операторами фактическую полезность сигналов тревоги. Знают ли они, что делать при сигнале? Способны ли быстро найти проблему и выполнить требуемые действия? Соответствует ли текст аварийного сигнала требованиям таблицы 3?

  3. Анализ и оценка производительности системы, а также сравнение с параметрами из таблиц 4 и 5. Начать следует с определения мешающих сигналов, а также сохраняющихся сигналов в нормальном состоянии и при запуске.

Благодарности

Авторы благодарны Viktor Leijon и Johan Nordlander за ценный вклад в модель сигналов тревоги.

Спасибо Nick Hancock, Joey Boyd, Tom Petch, Balazs Lengyel за рецензии и вклад в документ.

Адреса авторов

Stefan Vallin
Stefan Vallin AB
Email: stefan@wallan.se
 
Martin Bjorklund
Cisco
Email: mbj@tail-f.com

Перевод на русский язык

Николай Малых

nmalykh@protokols.ru

1Internet Engineering Task Force — комиссия по решению инженерных задач Internet.

2Internet Engineering Steering Group — комиссия по инженерным разработкам Internet.

3В оригинале ошибочно указано last-status-change. См. https://www.rfc-editor.org/errata/eid6866. Прим. перев.

4Secure Shell — защищённая оболочка.

5Опубликовано в RFC 9195. Прим. перев.

Рубрика: RFC | Оставить комментарий

RFC 8641 Subscription to YANG Notifications for Datastore Updates

Internet Engineering Task Force (IETF)                          A. Clemm
Request for Comments: 8641                                     Futurewei
Category: Standards Track                                        E. Voit
ISSN: 2070-1721                                            Cisco Systems
                                                          September 2019

Subscription to YANG Notifications for Datastore Updates

Подписка на уведомления YANG об обновлении хранилища данных

PDF

Аннотация

Этот документ описывает механизм, позволяющий приложениям-подписчикам запросить настраиваемый продолжающийся поток обновления от хранилища данных YANG. Такая видимость обновлений открывает новые возможности на основе отражения и мониторинга удалённых состояний конфигурации и работы.

Статус документа

Документ относится к категории Internet Standards Track.

Документ является результатом работы IETF1 и представляет согласованный взгляд сообщества IETF. Документ прошёл открытое обсуждение и был одобрен для публикации IESG2. Дополнительную информацию о стандартах Internet можно найти в разделе 2 RFC 7841.

Информацию о текущем статусе документа, ошибках и способах обратной связи можно найти по ссылке https://www.rfc-editor.org/info/rfc8641.

Авторские права

Авторские права (Copyright (c) 2019) принадлежат IETF Trust и лицам, указанным в качестве авторов документа. Все права защищены.

К документу применимы права и ограничения, указанные в BCP 78 и IETF Trust Legal Provisions и относящиеся к документам IETF (http://trustee.ietf.org/license-info), на момент публикации данного документа. Прочтите упомянутые документы внимательно. Фрагменты программного кода, включённые в этот документ, распространяются в соответствии с упрощённой лицензией BSD, как указано в параграфе 4.e документа IETF Trust Legal Provisions, без каких-либо гарантий (как указано в Simplified BSD License).

Документ может содержать материалы из IETF Document или IETF Contribution, опубликованных или публично доступных до 10 ноября 2008 года. Лица, контролирующие авторские права на некоторые из таких документов, могли не предоставить IETF Trust права разрешать внесение изменений в такие документы за рамками процессов IETF Standards. Без получения соответствующего разрешения от лиц, контролирующих авторские права этот документ не может быть изменён вне рамок процесса IETF Standards, не могут также создаваться производные документы за рамками процесса IETF Standards за исключением форматирования документа для публикации или перевода с английского языка на другие языки.

1. Введение

Традиционные подходы к обеспечению видимости управляемых объектов из удалённой системы основаны на опросе. При опросах данные периодически запрашиваются и извлекаются клиентом с сервера для поддержки их актуальности. Однако с управлением на основе опросов связаны некоторые проблемы.

  • Опросы связаны с существенной задержкой, которая препятствует использованию многих приложений.

  • Циклы опроса могут пропускаться, а запросы могут задерживаться или теряться, особенно в нагруженной сети, когда потребность в данных велика.

  • Запросы могут подвергаться флуктуациям, приводящим к различию интервалов опроса. Полученные данные сложно калибровать и сравнивать.

  • Для приложений, отслеживающих изменения, многие циклы удалённого опроса создают нежелательную и, в конечном итоге, расточительную нагрузку на сеть, устройства и приложения, особенно при редких измерениях.

Эффективной альтернативой запросам является получение автоматических продолжающихся обновлений от нужного набора хранилищ данных. Поэтому есть потребность в службе, которая (1) позволяет приложениям подписываться на обновления хранилищ данных и (2) позволяет серверам (их ещё называют издателями — publisher) выталкивать (push) данные передавая обновления, по сути, в режиме потока. Требования к таким службам приведены в [RFC7923].

Этот документ предлагает соответствующее решение на основе [RFC8639]. Дополнением к этой работе являются дополнения (augment) моделей данных YANG, расширенные RPC и определяемые хранилищами уведомления. Варианты транспорта, представленные в [RFC8639], хорошо подходят для этого решения.

2. Определения

Ключевые слова необходимо (MUST), недопустимо (MUST NOT), требуется (REQUIRED), нужно (SHALL), не следует (SHALL NOT), следует (SHOULD), не нужно (SHOULD NOT), рекомендуется (RECOMMENDED), не рекомендуется (NOT RECOMMENDED), возможно (MAY), необязательно (OPTIONAL) в данном документе интерпретируются в соответствии с BCP 14 [RFC2119] [RFC8174] тогда и только тогда, когда они выделены шрифтом, как показано здесь.

Документ использует термины из [RFC7950], [RFC8341], [RFC8342], [RFC8639] и добавляет термины, указанные ниже.

Datastore node — узел хранилища данных

Узел созданного экземпляра дерева данных YANG, связанный с хранилищем данных. В этом документе такие узлы часто называются объектами.

Datastore node update — обновление узла хранилища данных

Элемент данных, содержащий текущее значение узла datastore на момент создания обновления, а также путь к узлу хранилища данных.

Datastore subscription — описание хранилища данных

Подписка на поток обновления для узла хранилища данных.

Datastore subtree — субдерево (ветвь) хранилища данных

Узел хранилища данных и све его потомки datastore.

On-change subscription — подписка на изменения

Подписка на хранилище данных с уведомлениями при обнаружении изменения в хранилище.

Periodic subscription — периодическая подписка

Подписка на хранилище данных с уведомлениями через заданный интервал времени.

Selection filter — фильтр выбора

Оценка и/или выбор критерия, применяемого к целевому набору объектов.

Update record — запись обновления

Представление обновления одного или нескольких узлов хранилищ данных. Кроме того, запись может содержать сведения о том, какой тип обновления привёл у обновлению узла datastore (например, были ли узел datastore добавлен, изменён или удалён). В запись могут включаться другие метаданные, такие как идентификатор подписки, для которой создана запись. В документе записи обновления часто называются просто обновлением.

Update trigger — триггер обновления

Механизм, определяющий необходимость создания записи обновления.

YANG-Push

Механизм подписки и выталкивания обновлений хранилища данных, описанный в этом документе.

3. Обзор решения

Этот документ задаёт решение, обеспечивающее услуги подписки на обновления от хранилища данных. Поддерживаются динамические и настраиваемые подписки на обновления. Подписка задаёт, когда уведомления (их называют также push-обновлениями) следует передавать и какие данные включать в записи обновления. Обновления хранилищ данных последовательно выталкиваются (push) от издателя в соответствии с подпиской.

3.1. Модель подписки

Подписки YANG-Push определены с использованием модели данных YANG. Эта модель расширяет модель подписки, определённую в [RFC8639], возможностью подписки на обновления хранилищ данных, в частности, задания триггеров обновления, указывающих условия генерации записей обновления, а также их состав. Главные отличия указаны ниже.

  • Указание фильтров выбора, определяющих узлы и/или ветви хранилища данных, для которых выталкиваются обновления.

  • Указание правил обновления, включающих условия генерации и выталкивания новых записей. Имеется два типа подписок, различающиеся режимом отправки уведомлений — периодически или по факту изменения.

    • Для периодической подписки триггер обновлений указывается двумя параметрами, определяющими выталкивание обновлений. Эти параметру задают (1) интервал выталкивания обновления и (2) время привязки — anchor-time, т. е. точку отсчёта для вычисления моментов сборки и отправки периодических обновлений.

    • Для подписки on-change триггером обновлений является обнаружение изменений в сведениях, на которые организована подписка. Параметры управления описаны ниже.

      • dampening-period. При подписке на изменения уведомления следует передавать как можно быстрее. Однако частая отправка последовательности изменений может оказаться нежелательной, поскольку может требовать значительных ресурсов издателя или получателя. Для защиты от истощения ресурсов может применяться интервал демпфирования, задающий время ожидания перед генерацией последовательных записей обновления для одной подписки. Интервал демпфирования применяется ко всем узлам хранилища данных, выбранным в одной подписке. Это означает, что при обновлении одного или нескольких объектов запись для них создаётся незамедлительно (при отсутствии интервала демпфирования) или в конце заданного интервала демпфирования. Если в интервале демпфирования какой-либо объект меняется неоднократно, включается лишь значение на момент создания записи обновления. Интервал демпфирования начинается по завершении сборки записи обновления.

      • Параметр change-type может применяться для сокращения числа типов изменений, для которых передаются уведомления (например, можно передавать уведомления только при создании или удалении объекта, но не при его изменении).

      • Параметр sync-on-start определяет, будет ли применяться выталкивание всех обновлений (push-update, параграф 3.7) в начале подписки. Такая ранняя синхронизация задаёт «опорную точку» для последующих обновлений.

  • Кодирование (с использованием anydata) обновлений, выталкиваемых периодически или по изменению.

3.2. Согласование правил подписки

Запрос на динамическую подписку следует отклонена, если издатель понимает, что не может предоставить записи обновления в соответствии с запросом RPC establish-subscription или modify-subscription. В этом случае подписчик сможет быстро передать новый запрос RPC с другими параметрами.

Подписчику не следует пытаться угадать подходящие параметры. Поэтому для сокращения числа попыток подписки в динамической подписке поддерживается простое согласование параметров подписки между издателем и подписчиком. Согласование происходит путём включения дополнительной информации в отклик об ошибке для запроса RPC. Учёт возвращённых в сообщении об ошибке сведений позволит повысить вероятность успеха при последующем вызове RPC. Подсказки включают предлагаемые интервалы периодических обновлений, приемлемы интервалы демпфирования, оценку числа объектов, возвращаемых при использовании предложенного фильтра отбора. Однако не даётся гарантии, что последующий запрос в соответствии с этими подсказками будет воспринят.

3.3. Обновления при изменении

Подписка on-change позволяет получать обновления при изменении целевых объектов. Такая подписка особенно полезна при нечастом изменении данных, требующем быстрого оповещения с минимальной задержкой после события.

Подписки на изменения обычно сложнее в реализации, чем периодические подписки, поэтому могут поддерживаться не всеми реализациями или не для каждого объекта.

Восприятие или отклонение запроса подписки на изменения, когда подписка включает объекты, для которых не поддерживаются уведомления при изменении, определяется реализацией издателя. Издатель может воспринять подписку на изменения даже при наличии в запросе объектов, для которых on-change не поддерживается. В этом случае обновления передаются лишь для поддерживаемых объектов, а прочие объекты исключаются из записей обновления даже при смене их значений. Чтобы подписчик мог определить объекты, поддерживающие уведомления при изменении, издатель помечает объекты должным образом. Поэтому подписчик принимает на себя ответственность за выбор нужных объектов. Маркировка объектов описана в параграфе 3.10.

Издатель может просто отклонять подписки on-change, содержащие объекты, для которых не поддерживаются уведомления при изменении. В случае настраиваемой подписки издатель может приостановить подписку.

Чтобы избавить получателей от лавины повторяющихся обновлений для подписки на быстро меняющиеся объекты или объекты с колеблющимися значениями, в подписке на изменения можно задать интервал демпфирования. После создания записи для объекта с таким интервалом новые записи о его изменениях не будут создаваться, пока не закончится интервал демпфирования. В конце периода демпфирования передаются текущие значения для всех изменённых объектов. Изменёнными считаются также объекты, созданные или удалённые в интервале демпфирования. Если объект вернулся к первоначальному значению или был создан и удалён в интервале демпфирования, текущее значение (а не промежуточные обновления) все равно будет передано. Это указывает, что на объекте происходили изменения.

Подписки на изменения можно уточнять, указывая лишь некоторые типы изменений. Например, подписчик может получать уведомления лишь о создании и удалении объектов, но не о смене их значений.

С учётом сказанного выше процесс создания записи об обновлении в подписке на изменения показан ниже.

  1. Перед изменением или в начале интервала демпфирования применяется фильтрация и правила контроля доступа для проверки полномочий подписчика на просмотр соответствующих узлов хранилища (отфильтровываются ненужные узлы). Результатом является набор ветвей и узлов хранилища A.

  2. Перед изменением или в конце интервала демпфирования применяется фильтрация и правила контроля доступа (возможно, новые). Результатом является набор ветвей и узлов хранилища B.

  3. Создаётся запись для обновления путём применения записи YANG Patch [RFC8072] для перехода от A к B.

  4. Если A и B имеются различия, аннулирующие друг друга, в запись YANG Patch помещается последнее изменение даже при совпадении нового значения с исходным (в результате отмены внесённых изменений последующими). Если изменения включают создание нового узла в хранилище и его последующее удаление, запись YANG Patch будет указывать удаление. Если же узел был удалён и создан заново, запись YANG Patch будет показывать создание узла.

  5. Если полученная запись YANG Patch не пуста, она передаётся получателю.

Примечание. Если подписчик хочет задать разные интервалы демпфирования для разных объектов, он может организовать несколько подписок с разными фильтрами.

3.4. Вопросы надёжности

Подписка на обновления хранилища предназначена для избавления от опросов. Однако при этом важно, чтобы подписчики могли полагаться на подписку и быть уверенными в получении интересующих обновлений, не заботясь от том, что обновления могут быть незаметно отброшены. Иными словами, подписка является обещанием издателя предоставлять обновления получателям в соответствии с условиями подписки.

Однако имеется много причин, по которым издатель не может выполнять условия подписки, даже если та была создана с его согласия. Например, число узлов данных в хранилище может быть больше ожидаемого, а интервал -слишком коротким для быстрой отправки полной серии обновлений или внутренние проблемы могут мешать сбору объектов. По этим причинам предложенное в документе решение (1) требует от издателя уведомлять получателей при невозможности выполнять условия подписки и (2) предоставляет издателю возможность приостановить подписку в таких случаях. Это включает указание неполноты обновления в уведомлении push-update или push-change-update, а также отправку уведомлений subscription-suspended, когда это применимо. Описание этого дано в параграфе 3.11.1.

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

Решение основано на [RFC8639], где указано, что любая потеря связности в базовом транспорте будет обнаруживаться и приведёт к прерыванию (для динамической подписки) или приостановке (для настраиваемой подписки), гарантируя, что потеря уведомлений об изменениях не пройдёт незамеченной.

3.5. Кодирование данных

3.5.1. Периодические подписки

При периодической подписке данные, включённые как часть записи обновления, соответствуют данным, которые можно было прочитать с помощью операции извлечения.

3.5.2. Подписки на изменения

При подписке на изменения записи обновления должны указывать не только значения изменённых узлов хранилища данных, но и типы изменений с момента предыдущего обновления. Поэтому правила кодирования данных в обновлениях on-change обычно следуют операциям YANG Patch, заданным в [RFC8072]. Эти операции указывают, что нужно применить к состоянию из предыдущего обновления, чтобы получить новое состояние. Отметим, что объекты, в обновлении могут включать не только данные конфигурации, но и иные объекты (включая рабочие данные), тогда как исправления (patch) [RFC8072] применяются лишь к данных конфигурации в конфигурационных хранилищах.

Издатель указывает тип изменения узла в хранилище данных с помощью операций YANG Patch — create служит для недавно созданных объектов (кроме записей упорядоченного пользователем списка), delete — для удалённых объектов (включая упорядоченные пользователем списки), replace — только при изменения значения объекта, insert — при вставке в список нового объекта, move — при перемещении записи в упорядоченном пользователем списке.

Однако патч должен делать больше, чем просто описывать отличие предыдущего состояния объекта от текущего. В соответствии с параграфом 3.3 требуется также определить, происходили ли изменения в интервале демпфирования. Для этого допустимо кодировать операцию YANG Patch так, чтобы её применение не приводило к изменению текущего состояния по сравнению с предыдущим. Это указывает, что на объекте происходили какие-то действия. Примером может служить патч, который указывает, операцию create для хранилища данных, когда получатель полагает, что объект уже существует, или операцию replace которая «меняет» прежнее состояние на такое же. Отметим, что это означает, что указанные в параграфе 2.5 [RFC8072] ошибки операций create и delete не являются ошибками в случае YANG-Push (т. е. считаются корректными операциями для YANG-Push).

3.6. Указание отбора в хранилище

В подписке должны быть указаны фильтры отбора и хранилище данных, к которому эти фильтры применяются. Эти сведения служат для выбора и последующей передачи данных из хранилища издателя получателям.

К подписке в каждый момент может применяться лишь 1 фильтр и запрос RPC, задающий новый фильтр, будет переписывать имеющийся. Ниже указаны типы фильтров, включённые в модель YANG-Push, которые можно применить к хранилищу данных.

subtree

Фильтр выбора ветвей указывает одну или несколько ветвей дерева. При указании этого фильтра записи обновления будут исходить лишь из узлов данных указанных ветвей хранилища. Синтаксис и семантика соответствуют заданным в разделе 6 [RFC6241].

xpath

Фильтр xpath — это выражение XPath3, возвращающее набор узлов, для которых будут передаваться обновления.

Эти фильтры служат селекторами, определяющими объекты, попадающий в сферу действия подписки. Издатель должен поддерживать хотя бы один тип фильтров отбора.

XPath обеспечивает мощные средства фильтрации и при создании фильтров нужно соблюдать осторожность. Примером может быть фильтр XPath, который пропускает лишь узел хранилища с активным (up) интерфейсом. Получатель должен понимать влияние отсутствия или наличия объектов в каждом обновлении.

Когда набор критериев фильтра применяется к периодической подписке, критерии используются при каждом создании записи обновления и получателю передаются лишь узлы хранилища, соответствующие фильтру, к которым получатель имеет доступ. Если тот же фильтр применяется к подписке on-change, передаются сведения лишь для части узлов, поддерживающих уведомления при изменении. Узел хранилища, не поддерживающий on-change, не будет передаваться в push-update или push-change-update при подписке on-change (параграф 3.7).

3.7. Потоковые обновления

В отличие от традиционных запросов на извлечение данных, подписка на хранилище позволяет передать неограниченную по времени серию обновлений в форме потока. Для этого определены два базовых уведомления YANG — push-update и push-change-update.

Уведомление push-update задаёт полные, фильтруемые уведомления для обновлений хранилища данных в соответствии с условиями подписки. Этот тип уведомлений YANG применяется для постоянных уведомлений в периодической подписке и может также служить для подписки on-change в двух случаях. Во-первых, начальное уведомление push-update должно применяться при старте новой подписки для синхронизации получателя. Во-вторых, оно может передаваться, если позднее получатель решит снова синхронизировать подписку on-change. Запись обновления push-update содержит экземпляр ветви со всем содержимым, заданным подпиской. Это содержимое эквивалентно данным, которые были бы получены из хранилища явной операцией извлечения с использованием того же транспорта и фильтров.

Обновление push-change-update более распространено для подписок on-change. Запись обновления в этом случае включает набор изменений в узлах хранилища с момента отправки предыдущего сообщения. Иными словами, оно указывает узлы, которые были созданы, удалены или изменили свои значения. Когда в интервале демпфирования происходит несколько изменений и объект не удаляется, указывается последнее значение, т. е. для каждого объекта передаётся лишь одно изменение, а не вся история (иначе не было бы смысла задавать интервал демпфирования).

Сведения push-update и push-change-update кодируются и помещаются в уведомления, которые ставятся в выходную очередь для заданного транспорта.

На рисунке 1 приведён пример уведомления для подписки, отслеживающей рабочее состояние одного интерфейса Ethernet (в соответствии с [RFC8343]). Данные кодируются в XML [W3C.REC-xml-20081126] и передаются по протоколу управления сетью (Network Configuration Protocol или NETCONF) [RFC8640].

  <notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0">
   <eventTime>2017-10-25T08:00:11.22Z</eventTime>
   <push-update xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
     <id>1011</id>
     <datastore-contents>
        <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
         <interface>
           <name>eth0</name>
           <oper-status>up</oper-status>
         </interface>
       </interfaces>
     </datastore-contents>
   </push-update>
  </notification>

Рисунок 1. Пример выталкивания.

На рисунке 2 приведён пример сообщения on-change для такой же подписки.

  <notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0">
   <eventTime>2017-10-25T08:22:33.44Z</eventTime>
   <push-change-update
        xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
     <id>89</id>
     <datastore-changes>
       <yang-patch>
         <patch-id>0</patch-id>
         <edit>
           <edit-id>edit1</edit-id>
           <operation>replace</operation>
           <target>/ietf-interfaces:interfaces</target>
           <value>
             <interfaces
                  xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
               <interface>
                 <name>eth0</name>
                 <oper-status>down</oper-status>
               </interface>
             </interfaces>
           </value>
         </edit>
       </yang-patch>
     </datastore-changes>
   </push-change-update>
  </notification>

Рисунок 2. Пример выталкивания для уведомления On-Change.

В примере patch-id имеет значение 0. В соответствии с [RFC8072] patch-id является произвольной строкой. При использовании YANG-Push издателю следует помещать в patch-id значение счётчика, начинающегося с 0 и инкрементируемое при каждой следующей генерации push-change-update для подписки. При использовании в качестве счётчика он должен сбрасываться в 0 при каждой ресинхронизации (т. е. при передаче push-update), а также по достижении максимального значения 4294967295 (предельное значение для типа uint32). Это позволяет легко обнаруживать потери или нарушение порядка записей обновления.

3.8. Управление подписками

Определённые в [RFC8639] RPC были усовершенствованы для поддержки подписки на хранилища данных. Были также добавлены коды ошибок, указывающие причины отказа в подписке и новые yang-data, которые можно применять для включения деталей входных параметров для успеха последующего вызова RPC.

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

Если при отказе в подписке на хранилище данных в отклик включаются советы по параметрам, их следует передавать в контейнере yang-data establish-subscription-datastore-error-info, помещённом в отклик об ошибке RPC вместо establish-subscription-stream-error-info, используемого в случае потоковой подписки. На рисунке 3 показано дерево establish-subscription-datastore-error-info с использованием нотации [RFC8340].

          yang-data establish-subscription-datastore-error-info
            +--ro establish-subscription-datastore-error-info
               +--ro reason?                identityref
               +--ro period-hint?           centiseconds
               +--ro filter-failure-hint?   string
               +--ro object-count-estimate? uint32
               +--ro object-count-limit?    uint32
               +--ro kilobytes-estimate?    uint32
               +--ro kilobytes-limit?       uint32

Рисунок 3. Дерево establish-subscription-datastore-error-info.

В случае отказа на изменение подписки с включениям советов их следует помещать в контейнер yang-data modify-subscription-datastore-error-info в отклике об ошибке RPC вместо modify-subscription-stream-error-info, используемого для потоковой подписки. На рисунке 4 показано дерево modify-subscription-datastore-error-info.

          yang-data modify-subscription-datastore-error-info
            +--ro modify-subscription-datastore-error-info
               +--ro reason?                identityref
               +--ro period-hint?           centiseconds
               +--ro filter-failure-hint?   string
               +--ro object-count-estimate? uint32
               +--ro object-count-limit?    uint32
               +--ro kilobytes-estimate?    uint32
               +--ro kilobytes-limit?       uint32

Рисунок 4. Дерево modify-subscription-datastore-error-info.

3.9. Проверка прав получателя

Получателю данных подписки должны передавать лишь уведомления, на которые он имеет соответствующие права доступа. Издатель должен предотвращать включение в выталкиваемые данные сведений, для которых у получателя нет прав доступа. Для этого нужно применять все соответствующие проверки при выталкивании обновления с удаление при необходимости данных из ветвей хранилища, к которым получателю не предоставлен доступ. Это позволяет проверять права доступа к выталкиваемым по подписке данным YANG как при их обычном извлечении (get).

К каждому push-update и push-change-update должны применяться правила контроля доступа, как показано на рисунке 5. Это включает проверку наличия прав чтения для любого нового объекта, выбранного после отправки предыдущего уведомления конкретному получателю. Издатель должен без уведомления исключать узлы данных, которые получателю не разрешено видеть. Для реализации этого следует применять концептуальную модель проверки полномочий из [RFC8341] (в частности, параграф 3.2.4), расширенную для узлов данных в уведомлениях, а не только в сообщениях <rpc-reply> в ответ на запросы <get> и <get-config>.

                     +-----------------+      +--------------------+
push-update или -->  |  доступ к узлу  |  да  |   узел хранилища   |
push-change-update   |хранил. разрешен?| ---> |добавляется в запись|
                     +-----------------+      +--------------------+

Рисунок 5. Контроль доступа для Push-обновлений.


Издатель должен разрешать указание в фильтре подписки отсутствующих данных и данных, к которым получателю не разрешён доступ. Это позволяет получателю отслеживать весь жизненный цикл определённого дерева хранилища данных без необходимости явно указывать каждый узел. Если после применения правил контроля доступа не остаётся элементов для записи обновления, результат зависит от типа подписки. Для периодической подписки должно передаваться пустое обновление push-update, чтобы клиент не думал о потере обновления. Для подписки on-change передавать уведомление push-update недопустимо, чтобы клиент не узнал об изменениях в узлах, к которым у него нет доступа для чтения. Изменениям в фильтрах недопустимо влиять на интервалы демпфирования.

Издатель может отклонить запрос establish-subscription для несуществующих данных или данных, к которым у получателя нет доступа. В этом случае следует возвращать unchanging-selection как идентификатор причины отказа. Кроме того, издатель может прервать динамическую подписку или приостановить настраиваемую при изменении прав доступа получателя или правил доступа к объектам подписки. В таких случаях издетелю следует указывать unchanging-selection как причину отказа при отправке subscription-terminated или subscription-suspended. Такая возможность позволяет издателю избежать необходимости поддерживать постоянную и полную фильтрацию содержимого подписки для каждой записи обновления, а также снижает выроятность утечки контролируемых объектов.

Если доступ для чтения ранее доступных узлов был утрачен в результате смены прав получателя, это следует указать как операцию delete для подписки on-change. Если не удаётся обработать такие изменения прав получателей с помощью delete, реализация издателя должна инициировать повторную организацию динамической подписки или повторную инициализацию настраиваемой подписки, чтобы установить соответствующие фильтры.

3.10. Узлы хранилища с уведомлением при изменении

В некоторых случаях издатель, поддерживающий уведомления при изменении, не способен выталкивать обновления on-change для некоторых типов объектов. Причиной этого могут быть частые изменения узлов хранилища данных (например, счётчиков октетов [RFC8343]), частые и малозначимые изменения мелких объектов (например, изменение температуры на 0,1 градуса) или неспособность реализации передавать такие уведомления для конкретного объекта.

В таких случаях для клиентских приложений важна возможность определить, для каких объектов поддерживаются и не поддерживаются уведомления при изменении. Иначе приложения не будут знать, могут ли они полагаться на подписку on-change для получения интересующих уведомлений об изменениях. Иными словами, если реализация не предоставляет решения или поддерживает поддерживает полные уведомления об изменениях, у клиентов такой реализации не будет возможности узнать область действия их подписки on-change.

Поэтому реализациям настоятельно рекомендуется предоставлять решение этой проблемы. Одним из вариантов может быть предоставление клиентам возможности узнать, для каких объектов поддерживаются уведомления при изменении, с помощью другой модели данных YANG. Пример такого решения представлен в [Yang-Push-Notif-Cap]. До стандартизации этого решения реализациям следует предоставлять свои решения.

3.11. Другие вопросы

3.11.1. Отказоустойчивость и надёжность

Важно, чтобы описанные в этом документе обновления (в частности, on-change) не терялись. Если же потеря уведомлений неизбежна, получатель должен знать об этом.

Записи обновлений в одной подписке недопустимо переупорядочивать до транспортировки.

Вполне возможно, что при некоторых обстоятельствах издатель поймёт, что он не способен включить в запись обновления полный набор объектов, заданных условиями подписки. В таких случаях он должен действовать, как указано ниже.

  • Издатель должен установить флаг incomplete-update для любой записи, не содержащей всю информацию.

  • Издатель может приостановить подписку в соответствии с [RFC8639]. Если издатель совсем не создаёт запись обновления, он должен приостановить подписку.

  • При возобновлении подписки on-change издателю следует генерировать отличия (patch) от предыдущей. Если это невозможно и для подписки задано sync-on-start true, можно передать содержимое хранилища полностью через push-update (фактическая замена прежнего содержимого). Если и этот вариант невозможен, должен быть установлен флаг incomplete-update в следующем обновлении push-change-update.

Примечание. Вполне возможна постановка серии уведомлений push-change-update (и даже push-update) в очередь передачи на транспортном уровне. Издатель не обязан объединять записи обновления, переданные одновременно.

Действие получателя при наличии флага incomplete-update в записи обновления зависят от приложения. Можно просто ждать, не делая ничего, выполнить ресинхронизацию, активно извлекая все сведения для подписки, или прервать подписку и организовать новую, возможно с сокращением в ней числа объектов.

3.11.2. Возможности издателя

Предпочтительней отклонить запрос на подписку, нежели принять запрос, который невозможно выполнить.

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

4. Модель YANG для управления Push-подписками на хранилища

4.1. Обзор

Модель данных YANG для подписок с выталкиванием на зранилища данных показана на рисунках 6 — 9 с использованием деревьев с нотацией [RFC8340]. Заданные здесь новые объекты схемы (не присутствующие в [RFC8639]) указаны префиксом yp. Для удобства читателей размер деревьев сокращен путём исключения некоторых узлов данных модуля YANG ietf-subscribed-notifications [RFC8639], не существенных для понимания, с заменой на «…».

Поскольку дерево достаточно велико, оно разделено на 4 части. На рисунке 6 показаны дополнения модуля YANG ietf-yang-push для конфигурации подписки, указанной в модуле YANG ietf-subscribed-notifications.

Модуль ietf-subscribed-notifications

     ...
     +--rw filters
     |  ...
     |  +--rw yp:selection-filter* [filter-id]
     |     +--rw yp:filter-id                   string
     |     +--rw (yp:filter-spec)?
     |        +--:(yp:datastore-subtree-filter)
     |        |  +--rw yp:datastore-subtree-filter?   <anydata>
     |        |          {sn:subtree}?
     |        +--:(yp:datastore-xpath-filter)
     |           +--rw yp:datastore-xpath-filter?     yang:xpath1.0
     |                   {sn:xpath}?
     +--rw subscriptions
        +--rw subscription* [id]
           |  ...
           +--rw (target)
           |  +--:(stream)
           |  |   ...
           |  +--:(yp:datastore)
           |     +--rw yp:datastore                     identityref
           |     +--rw (yp:selection-filter)?
           |        +--:(yp:by-reference)
           |        |  +--rw yp:selection-filter-ref
           |        |          selection-filter-ref
           |        +--:(yp:within-subscription)
           |           +--rw (yp:filter-spec)?
           |              +--:(yp:datastore-subtree-filter)
           |              |  +--rw yp:datastore-subtree-filter?
           |              |          <anydata> {sn:subtree}?
           |              +--:(yp:datastore-xpath-filter)
           |                 +--rw yp:datastore-xpath-filter?
           |                         yang:xpath1.0 {sn:xpath}?
           | ...
           +--rw (yp:update-trigger)
              +--:(yp:periodic)
              |  +--rw yp:periodic!
              |     +--rw yp:period         centiseconds
              |     +--rw yp:anchor-time?   yang:date-and-time
              +--:(yp:on-change) {on-change}?
                 +--rw yp:on-change!
                    +--rw yp:dampening-period?   centiseconds
                    +--rw yp:sync-on-start?      boolean
                    +--rw yp:excluded-change*    change-type

Рисунок 6. Структура модели данных — конфигурация подписки.

На рисунке 7 показаны дополнения из модуля YANG ietf-yang-push для RPC, заданных в модуле YANG ietf-subscribed-notifications [RFC8639]. В частности, эти дополнения касаются RPC establish-subscription и modify-subscription, в которые дабавлены параметры, требуемые для задания push-подписки на хранилища данных.

     rpcs:
       +---x establish-subscription
       |  +---w input
       |  |  ...
       |  |  +---w (target)
       |  |  |  +--:(stream)
       |  |  |  |  ...
       |  |  |  +--:(yp:datastore)
       |  |  |     +---w yp:datastore                   identityref
       |  |  |     +---w (yp:selection-filter)?
       |  |  |        +--:(yp:by-reference)
       |  |  |        |  +---w yp:selection-filter-ref
       |  |  |        |          selection-filter-ref
       |  |  |        +--:(yp:within-subscription)
       |  |  |           +---w (yp:filter-spec)?
       |  |  |              +--:(yp:datastore-subtree-filter)
       |  |  |              |  +---w yp:datastore-subtree-filter?
       |  |  |              |          <anydata> {sn:subtree}?
       |  |  |              +--:(yp:datastore-xpath-filter)
       |  |  |                 +---w yp:datastore-xpath-filter?
       |  |  |                         yang:xpath1.0 {sn:xpath}?
       |  |  | ...
       |  |  +---w (yp:update-trigger)
       |  |     +--:(yp:periodic)
       |  |     |  +---w yp:periodic!
       |  |     |     +---w yp:period         centiseconds
       |  |     |     +---w yp:anchor-time?   yang:date-and-time
       |  |     +--:(yp:on-change) {on-change}?
       |  |        +---w yp:on-change!
       |  |           +---w yp:dampening-period?   centiseconds
       |  |           +---w yp:sync-on-start?      boolean
       |  |           +---w yp:excluded-change*    change-type
       |  +--ro output
       |     +--ro id                            subscription-id
       |     +--ro replay-start-time-revision?   yang:date-and-time
       |             {replay}?
       +---x modify-subscription
       |  +---w input
       |     ...
       |     +---w (target)
       |     |  ...
       |     |  +--:(yp:datastore)
       |     |     +---w yp:datastore                   identityref
       |     |     +---w (yp:selection-filter)?
       |     |        +--:(yp:by-reference)
       |     |        |  +---w yp:selection-filter-ref
       |     |        |          selection-filter-ref
       |     |        +--:(yp:within-subscription)
       |     |           +---w (yp:filter-spec)?
       |     |              +--:(yp:datastore-subtree-filter)
       |     |              |  +---w yp:datastore-subtree-filter?
       |     |              |          <anydata> {sn:subtree}?
       |     |              +--:(yp:datastore-xpath-filter)
       |     |                 +---w yp:datastore-xpath-filter?
       |     |                         yang:xpath1.0 {sn:xpath}?
       |     | ...
       |     +---w (yp:update-trigger)
       |        +--:(yp:periodic)
       |        |  +---w yp:periodic!
       |        |     +---w yp:period         centiseconds
       |        |     +---w yp:anchor-time?   yang:date-and-time
       |        +--:(yp:on-change) {on-change}?
       |           +---w yp:on-change!
       |              +---w yp:dampening-period?   centiseconds
       +---x delete-subscription
       |  ...
       +---x kill-subscription
          ...

     yang-data (для сообщений об ошибках RPC)
       ...

Рисунок 7. Структура модели данных — RPC.

На рисунке 8 показаны дополнения из модуля YANG ietf-yang-push для уведомлений, заданных в модуле YANG ietf-subscribed-notifications. Эти дополнения позволяют включать параметры конфигурации подписки на хранилище данных в уведомления subscription-started и subscription-modified.

     notifications:
       +---n replay-completed {replay}?
       |  ...
       +---n subscription-completed
       |  ...
       +---n subscription-started {configured}?
       |  |  ...
       |  +--ro (target)
       |  |  ...
       |  |  +--:(yp:datastore)
       |  |     +--ro yp:datastore                   identityref
       |  |     +--ro (yp:selection-filter)?
       |  |        +--:(yp:by-reference)
       |  |        |  +--ro yp:selection-filter-ref
       |  |        |          selection-filter-ref
       |  |        +--:(yp:within-subscription)
       |  |           +--ro (yp:filter-spec)?
       |  |              +--:(yp:datastore-subtree-filter)
       |  |              |  +--ro yp:datastore-subtree-filter?
       |  |              |          <anydata> {sn:subtree}?
       |  |              +--:(yp:datastore-xpath-filter)
       |  |                 +--ro yp:datastore-xpath-filter?
       |  |                         yang:xpath1.0 {sn:xpath}?
       |  ...
       |  +--ro (yp:update-trigger)
       |     +--:(yp:periodic)
       |     |  +--ro yp:periodic!
       |     |     +--ro yp:period         centiseconds
       |     |     +--ro yp:anchor-time?   yang:date-and-time
       |     +--:(yp:on-change) {on-change}?
       |        +--ro yp:on-change!
       |           +--ro yp:dampening-period?   centiseconds
       |           +--ro yp:sync-on-start?      boolean
       |           +--ro yp:excluded-change*    change-type
       +---n subscription-resumed
       |  ...
       +---n subscription-modified
       |  ...
       |  +--ro (target)
       |  |  |  ...
       |  |  +--:(yp:datastore)
       |  |     +--ro yp:datastore                   identityref
       |  |     +--ro (yp:selection-filter)?
       |  |        +--:(yp:by-reference)
       |  |        |  +--ro yp:selection-filter-ref
       |  |        |          selection-filter-ref
       |  |        +--:(yp:within-subscription)
       |  |           +--ro (yp:filter-spec)?
       |  |              +--:(yp:datastore-subtree-filter)
       |  |              |  +--ro yp:datastore-subtree-filter?
       |  |              |          <anydata> {sn:subtree}?
       |  |              +--:(yp:datastore-xpath-filter)
       |  |                 +--ro yp:datastore-xpath-filter?
       |  |                         yang:xpath1.0 {sn:xpath}?
       |  ...
       |  +--ro (yp:update-trigger)?
       |     +--:(yp:periodic)
       |     |  +--ro yp:periodic!
       |     |     +--ro yp:period         centiseconds
       |     |     +--ro yp:anchor-time?   yang:date-and-time
       |     +--:(yp:on-change) {on-change}?
       |        +--ro yp:on-change!
       |           +--ro yp:dampening-period?    centiseconds
       |           +--ro yp:sync-on-start?       boolean
       |           +--ro yp:excluded-change*     change-type
       +---n subscription-terminated
       |  ...
       +---n subscription-suspended
          ...

Рисунок 8. Структура модели данных — уведомления.

На рисунке 9 приведены добавленные этим документов части модуля YANG ietf-yang-push, не являющиеся дополнениями других модулей YANG.

Модуль ietf-yang-push

     rpcs:
       +---x resync-subscription {on-change}?
          +---w input
             +---w id    sn:subscription-id

     yang-data (for placement into RPC error responses):
       +-- resync-subscription-error
       |  +--ro reason?                   identityref
       |  +--ro period-hint?              centiseconds
       |  +--ro filter-failure-hint?      string
       |  +--ro object-count-estimate?    uint32
       |  +--ro object-count-limit?       uint32
       |  +--ro kilobytes-estimate?       uint32
       |  +--ro kilobytes-limit?          uint32
       +-- establish-subscription-error-datastore
       |  +--ro reason?                   identityref
       |  +--ro period-hint?              centiseconds
       |  +--ro filter-failure-hint?      string
       |  +--ro object-count-estimate?    uint32
       |  +--ro object-count-limit?       uint32
       |  +--ro kilobytes-estimate?       uint32
       |  +--ro kilobytes-limit?          uint32
       +-- modify-subscription-error-datastore
          +--ro reason?                   identityref
          +--ro period-hint?              centiseconds
          +--ro filter-failure-hint?      string
          +--ro object-count-estimate?    uint32
          +--ro object-count-limit?       uint32
          +--ro kilobytes-estimate?       uint32
          +--ro kilobytes-limit?          uint32

        notifications:
          +---n push-update
          |  +--ro id?                   sn:subscription-id
          |  +--ro datastore-contents?   <anydata>
          |  +--ro incomplete-update?    empty
          +---n push-change-update {on-change}?
             +--ro id?                   sn:subscription-id
             +--ro datastore-changes
             |  +--ro yang-patch
             |     +--ro patch-id    string
             |     +--ro comment?    string
             |     +--ro edit* [edit-id]
             |        +--ro edit-id      string
             |        +--ro operation    enumeration
             |        +--ro target       target-resource-offset
             |        +--ro point?       target-resource-offset
             |        +--ro where?       enumeration
             |        +--ro value?       <anydata>
             +--ro incomplete-update?    empty

Рисунок 9. Структура модели данных — новые части.

Некоторые компоненты модели данных описаны ниже.

4.2. Настройка подписки

Настраиваемые и динамические подписки представлены листом subscription. Ниже указаны новые параметры, расширяющие модель данных подписки из [RFC8639].

  • Целевое хранилище, из которого извлекаются данные. Возможные хранилища включают указанные в [RFC8342]. Платформа может также поддерживать своё хранилище данных.

  • Фильтр выбора интересующих узлов YANG в хранилище данных. Содержимое фильтра задаётся ссылкой на имеющийся фильтр или встроенным определением лишь для этой подписки. Указание фильтров ссылкой позволяет реализации избежать проверки приемлемости фильтра при запросе динамической подписки. Оператор case применяется для задания вариантов.

  • Для периодической подписки триггерные обновления будут происходить на границах заданного интервала времени, которые могут быть рассчитаны по параметрам подписки:

    • period задаёт интервал между выталкиваниями обновлений;

    • anchor-time задаёт начальное время для отсчёта интервалов обновления; если этот параметр не задан, в качестве начального времени должен устанавливаться момент создания первой записи с обновлением.

  • Для подписки on-change при условии завершения интервала демпфирования выталкивание происходит при обновлении информации для подписки. Подписки on-change имеют более сложную семантику, определяемую своим набором параметров:

    • dampening-period задаёт интервал, который должен пройти до отправки следующего обновления в подписке, т. е. каждое новое уведомление передаётся не раньше dampening-period после предыдущего;

    • excluded-change позволяет ограничить типы изменений, для которых следует передавать обновления (например, добавлять запись обновления только при создании объекта);

    • sync-on-start указывает, нужно ли передавать полное обновление всех данных в начале подписки.

4.3. Уведомления YANG

4.3.1. Уведомления о смене состояния

Применяются механизмы и уведомления для состояния подписки из [RFC8639]. Уведомления subscription-started и subscription-modified дополнены (augment) для включения объектов, связанных с хранилищем данных.

4.3.2. Уведомления для содержимого подписки

Кроме содержимого подписки уведомления push-update и push-change-update могут включать другие объекты.

  • Идентификатор подписки (id) должен передаваться вместе с содержимым. Это позволяет получателю связать запись обновления с конкретной подпиской.

  • Лист incomplete-update указывает, что не все изменения, произошедшие с момента предыдущего обновления, были включены в данное обновление. Иными словами, издатель не смог полностью выполнить свои обязательства по подписке, например, хранилище не смогло предоставить процессу издателя полный набор своих узлов. Для ресинхронизации подписки on-change издатель может передать следом push-update с моментальным снимком (snapshot) данных подписки.

4.4. YANG RPC

Подписки YANG-Push организуются, изменяются и удаляются с применением дополненных RPC из [RFC8639].

4.4.1. establish-subscription

Подписчик передаёт RPC establish-subscription с параметрами, указанными в параграфе 3.1. Например,

 <netconf:rpc message-id="101"
     xmlns:netconf="urn:ietf:params:xml:ns:netconf:base:1.0">
   <establish-subscription
       xmlns="urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications"
       xmlns:yp="urn:ietf:params:xml:ns:yang:ietf-yang-push">
     <yp:datastore
          xmlns:ds="urn:ietf:params:xml:ns:yang:ietf-datastores">
       ds:operational
     </yp:datastore>
     <yp:datastore-xpath-filter
         xmlns:ex="https://example.com/sample-data/1.0">
       /ex:foo
     </yp:datastore-xpath-filter>
     <yp:periodic>
       <yp:period>500</yp:period>
     </yp:periodic>
   </establish-subscription>
 </netconf:rpc>

Рисунок 10. RPC establish-subscription.

Позитивный отклик включает идентификатор воспринятой подписки (id) и может иметь вид

 <rpc-reply message-id="101"
    xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
    <id
      xmlns="urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications">
       52
    </id>
 </rpc-reply>

Рисунок 11. RPC establish-subscription с позитивным откликом.

Подписка может быть отвергнута по разным причинам, включая отсутствие прав на её организацию, нехватка у издателя возможностей для обслуживания, неспособность издателя извлекать содержимое хранилища данных с запрошенной периодичностью.

Если запрос отклонён из-за несособности издатедя обслужить его, издателю следует включить в отклик об ошибке советы, которые помогут подписчику задать приемлемые параметры для следующего запроса подписки. Эти подсказки включаются в структуру yang-data establish-subscription-error-datastore. Однако даже следование подсказкам не гарантирует успешной подписки.

Конкретные параметры, возвращаемые в отклике об ошибке RPC, зависят от применяемого для поддержки подписки транспорта. Для NETCONF такие параметры определены в [RFC8640]. Например, запрос NETCONF может иметь вид

     <rpc message-id="101"
          xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
       <establish-subscription
           xmlns=
             "urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications"
           xmlns:yp="urn:ietf:params:xml:ns:yang:ietf-yang-push">
         <yp:datastore
             xmlns:ds="urn:ietf:params:xml:ns:yang:ietf-datastores">
           ds:operational
         </yp:datastore>
         <yp:datastore-xpath-filter
             xmlns:ex="https://example.com/sample-data/1.0">
           /ex:foo
         </yp:datastore-xpath-filter>
         <yp:on-change>
           <yp:dampening-period>100</yp:dampening-period>
         </yp:on-change>
       </establish-subscription>
     </rpc>

Рисунок 12. Запрос establish-subscription, пример 2.

Издатель, который не может обслужить обновления при изменении, но способен доставить периодические обновления, может передать отклик NETCONF вида

 <rpc-reply message-id="101"
   xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"
   xmlns:yp="urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications">
   <rpc-error>
     <error-type>application</error-type>
     <error-tag>operation-failed</error-tag>
     <error-severity>error</error-severity>
     <error-path>/yp:periodic/yp:period</error-path>
     <error-info>
       <yp:establish-subscription-error-datastore>
         <yp:reason>yp:on-change-unsupported</yp:reason>
       </yp:establish-subscription-error-datastore>
     </error-info>
   </rpc-error>
 </rpc-reply>

Рисунок 13. establish-subscription с откликом об ошибке, пример 2.

4.4.2. modify-subscription

Подписчик может вызвать RPC modify-subscription для организованной ранее подписки, включая в этот вызов желаемые значения параметров подписки. Не включённые в запрос параметры должны оставаться неизменными. На рисунке 14 показан пример попытки подписчика изменить период и фильтр XPath для хранилища данных в подписке с использованием NETCONF.

     <rpc message-id="102"
          xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
       <modify-subscription
           xmlns=
             "urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications"
           xmlns:yp="urn:ietf:params:xml:ns:yang:ietf-yang-push">
         <id>1011</id>
         <yp:datastore
             xmlns:ds="urn:ietf:params:xml:ns:yang:ietf-datastores">
           ds:operational
         </yp:datastore>
         <yp:datastore-xpath-filter
             xmlns:ex="https://example.com/sample-data/1.0">
           /ex:bar
         </yp:datastore-xpath-filter>
         <yp:periodic>
           <yp:period>250</yp:period>
         </yp:periodic>
        </modify-subscription>
     </rpc>

Рисунок 14. Запрос modify-subscription.

Издатель должен отвечать на запрос изменения подписки. Если запрос отвергнут, имеющаяся подписка не меняется и издатель должен возвратить отклик об ошибке RPC, который может включать советы, инкапсулированные в структуру yang-data modify-subscription-error-datastore. Подписку можно изменять неоднократно.

Конкретные параметры, возвращаемые в отклике об ошибке RPC, зависят от транспорта, применяемого для поддержки подписки. Для NETCONF такие параметры заданы в [RFC8640].

Настраиваемые подписки нельзя изменить с помощью RPC modify-subscription. Вместо этого нужно вносить изменения в конфигурацию.

4.4.3. delete-subscription

Для прекращения приёма обновлений и фактического удаления подписки, организованной ранее с помощью RPC establish-subscription подписчик может передать RPC delete-subscription, принимающего на входе лишь идентификатор подписки (id). Вызов RPC заимствован из [RFC8639].

4.4.4. resync-subscription

Этот вызов RPC поддерживается лишь для подписок on-change, ранее созданных вызовом RPC establish-subscription, например

      <rpc message-id="103"
           xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
        <resync-subscription
            xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
          <id>1011</id>
        </resync-subscription>
      </rpc>

Рисунок 15. resync-subscription.

При получении вызова издатель должен (1) воспринять запрос и быстро передать push-update или (2) передать соответствующий отклик об ошибке RPC. В этот отклик издатель может включить структуру данных yang-data resync-subscription-error с дополнительными сведениями о причине ошибки.

4.4.5. Синхронизация модуля YANG

Для запроса подписки подписчику нужно знать используемые издателем схемы хранилищ данных YANG. Эти схемы доступны в модуле библиотеки YANG ietf-yang-library.yang, заданном в [RFC8525]. Предполагается, что получатель знает о библиотеке YANG до начала подписки.

Набор модулей, выпусков, свойств и отклонений может меняться в процессе работы (если это поддерживает реализация издателя). Для этого библиотека YANG предоставляет простое уведомление yang-library-change, информирующее подписчика об изменении библиотеки. В этом случае может потребоваться информирование получателя об изменении модуля для корректной обработки обновлений, связанных с узлами хранилища данных.

5. Модуль YANG для YANG-Push

Этот модуль YANG импортирует определения типов из [RFC6991], идентификаторы из [RFC8342], расширение yang-data из [RFC8040], группировку yang-patch из [RFC8072]. Кроме того, модуль импортирует дополнения многих определений из [RFC8639], а также ссылается на [RFC6241], [XPATH] (XML Path Language (XPath) Version 1.0) и [RFC7950].

   <CODE BEGINS> file "ietf-yang-push@2019-09-09.yang"
   module ietf-yang-push {
     yang-version 1.1;
     namespace "urn:ietf:params:xml:ns:yang:ietf-yang-push";
     prefix yp;

     import ietf-yang-types {
       prefix yang;
       reference
         "RFC 6991: Common YANG Data Types";
     }
     import ietf-subscribed-notifications {
       prefix sn;
       reference
         "RFC 8639: Subscription to YANG Notifications";
     }
     import ietf-datastores {
       prefix ds;
       reference
         "RFC 8342: Network Management Datastore Architecture (NMDA)";
     }
     import ietf-restconf {
       prefix rc;
       reference
         "RFC 8040: RESTCONF Protocol";
     }
     import ietf-yang-patch {
       prefix ypatch;
       reference
         "RFC 8072: YANG Patch Media Type";
     }

     organization
       "IETF NETCONF (Network Configuration) Working Group";
     contact
       "WG Web:  <https:/datatracker.ietf.org/wg/netconf/>  
        WG List: <mailto:netconf@ietf.org> 

        Author:  Alexander Clemm
                 <mailto:ludwig@clemm.org> 

        Author:  Eric Voit
                 <mailto:evoit@cisco.com>"; 

     description
       "Этот модуль содержит спецификации YANG для YANG-Push.

        Ключевые слова ДОЛЖНО, НЕДОПУСТИМО, ТРЕБУЕТСЯ, НУЖНО, НЕ НУЖНО, 
        СЛЕДУЕТ, НЕ СЛЕДУЕТ, РЕКОМЕНДУЕТСЯ, НЕ РЕКОМЕНДУЕТСЯ, МОЖНО,
        НЕОБЯЗАТЕЛЬНО в этом документе трактуются в соответствии с 
        BCP 14 (RFC 2119) (RFC 8174) тогда и только тогда, когда они
        указаны заглавными буквами, как показано здесь.

        Авторские права (Copyright (c) 2019) принадлежат IETF Trust и
        лицам, указанным как авторы. Все права защищены.

        Распространение и применение модуля в исходной или двоичной 
        форме с изменениями или без таковых разрешено в соответствии с
        лицензией Simplified BSD License, изложенной в параграфе 4.c
        IETF Trust's Legal Provisions Relating to IETF Documents
        (https://trustee.ietf.org/license-info). 

        Эта версия модуля YANG является частью RFC 8641, где правовые
        аспекты приведены более полно.";

     revision 2019-09-09 {
       description
         "Исходный выпуск.";
       reference
         "RFC 8641: Subscriptions to YANG Datastores";
     }

     /*
      * Свойства (функции)
      */

     feature on-change {
       description
         "Указывает поддержку подписки, вызываемой изменениями.";
     }

     /*
      * Отождествления (идентификаторы)
      */

     /* Идентификаторы типов ошибок для подписки на хранилище данных. */

     identity resync-subscription-error {
       description
         "Проблема при попытке выполнить запрос resync-subscription.";
     }

     identity cant-exclude {
       base sn:establish-subscription-error;
       description
         "Не удалось удалить набор параметров excluded-change. Это 
          означает, что издатель не может ограничить уведомления 
          push-change-update лишь типами изменений, запрошенные для
          этой подписки.";
     }

     identity datastore-not-subscribable {
       base sn:establish-subscription-error;
       base sn:subscription-terminated-reason;
       description
         "На это хранилище подписка невозможна.";
     }

     identity no-such-subscription-resync {
       base resync-subscription-error;
       description
         "Указанной подписки нет. Это может быть обусловлено ошибочным
          идентификатором подписки, идентификатором от другого 
          подписчика или идентификатором настраиваемой подписки.";
     }

     identity on-change-unsupported {
       base sn:establish-subscription-error;
       description
         "Подписка on-change не поддерживается для каких-либо объектов,
          выбираемых этим фильтром.";
     }

     identity on-change-sync-unsupported {
       base sn:establish-subscription-error;
       description
         "Ни sync-on-start, ни ресинхронизация не поддерживаются для
          этой подписки. Эта ошибка может использоваться в двух случаях:
          (1) RPC establish-subscription включает sync-on-start, но
          издатель не поддерживает отправку push-update для этой 
          подписки по причинам, отличным от on-change-unsupported и
          sync-too-big
          (2) вызван RPC resync-subscription для имеющейся периодической
          подписки или on-change без поддержки ресинхронизации.";
     }

     identity period-unsupported {
       base sn:establish-subscription-error;
       base sn:modify-subscription-error;
       base sn:subscription-suspended-reason;
       description
         "Запрошенный период или dampening-period слишком мал. Это
          возможно для периодических и on-change подписок (с
          демпфированием и без него). Могут дополнительно возвращаться
          советы по части приемлемого периода.";
     }

     identity update-too-big {
       base sn:establish-subscription-error;
       base sn:modify-subscription-error;
       base sn:subscription-suspended-reason;
       description
         "Размер деревьев периодического или on-change уведомления
          превышает допустимый. Советы с оценкой допустимого размера
          могут возвращаться как дополнение.";
     }

     identity sync-too-big {
       base sn:establish-subscription-error;
       base sn:modify-subscription-error;
       base resync-subscription-error;
       base sn:subscription-suspended-reason;
       description
         "Размер деревьев sync-on-start или ресинхронизации превышает
          допустимый. Могут дополнительно включаться советы с оценкой
          приемлемого размера.";
     }

     identity unchanging-selection {
       base sn:establish-subscription-error;
       base sn:modify-subscription-error;
       base sn:subscription-terminated-reason;
       description
         "Фильтр вряд ли выберет какие-либо узлы дерева данных. Это
          означает, что на основе текущих прав доступа подписчика
          издатель понимает, что выбор фильтром изменённых узлов дерева 
          маловероятен. Примерами могут служит отсутствие ветви или 
          прав у получателя, статические объекты, меняющиеся лишь 
          при перезагрузке.";
     }

     /*
      * Определения типов
      */

     typedef change-type {
       type enumeration {
         enum create {
           description
             "Изменение говорит о создании нового узла в хранилище.";
         }
         enum delete {
           description
             "Изменение говорит об удалении узла из хранилища.";
         }
         enum insert {
           description
             "Изменение говорит о вставке нового узла хранилища с 
              заданным пользователем порядком.";
         }
         enum move {
           description
             "Изменение говорит о смене порядка узлов в хранилище.";
         }
         enum replace {
           description
             "Изменение говорит о смене значения узла хранилища.";
         }
       }
       description
         "Указывает разные типы изменений в хранилище данных.

          Этот тип основан на операциях, заданных для YANG Patch, но
          отличается тем, что получатель может обрабатывать записи
          обновлений с операцией create на узле хранилища, который
          существует по мнению получателя, или удалять узел, которого
          по мнению получателя нет.";
       reference
         "RFC 8072: YANG Patch Media Type, Section 2.5";
     }

     typedef selection-filter-ref {
       type leafref {
         path "/sn:filters/yp:selection-filter/yp:filter-id";
       }
       description
         "Этот тип служит для указания фильтра отбора.";
     }

     typedef centiseconds {
       type uint32;
       description
         "Интервал времени в сотых долях секунды (0,01).";
     }

     /*
      * Определения групп
      */

     grouping datastore-criteria {
       description
         "Группировка для критериев, по которым объекты целевого
          хранилища данных следует включать в push-обновления.";
       leaf datastore {
         type identityref {
           base ds:datastore;
         }
         mandatory true;
         description
           "Хранилище, из которого извлекаются данные.";
       }
       uses selection-filter-objects;
     }

     grouping selection-filter-types {
       description
         "Группировка для типов селекторов объектов из хранилища.";
       choice filter-spec {
         description
           "Спецификация фильтра содержимого для этого запроса.";
         anydata datastore-subtree-filter {
           if-feature "sn:subtree";
           description
             "Указывает извлекаемые части целевого хранилища.";
           reference
             "RFC 6241: Network Configuration Protocol (NETCONF),
                        Section 6";
         }
         leaf datastore-xpath-filter {
           if-feature "sn:xpath";
           type yang:xpath1.0;
           description
             "Выражение XPath, указывающее извлекаемые части хранилища.

              Если выражение даёт набор узлов, все узлы этого набора
              выбираются фильтром. Иначе фильтр не возвращает ничего.

              Выражение оценивается в указанном ниже контексте.
              - Набор объявлений пространств имён - это набор пар 
                «префикс-пространство имен» для всех модулей YANG,
                реализованных сервером, где префиксом служит имя модуля
                YANG, а пространство имён задаёт оператор namespace в
                модуле YANG.
                Если лист кодируется в XML, все объявления пространств
                имён в области действия листа stream-xpath-filter
                добавляются к набору объявлений пространств имён. Если 
                префикс, найденный в XML, уже есть в наборе объявлений, 
                применяется пространство имён в XML.
              - Набор привязок переменных пуст.
              - Библиотека функций состоит из ядра библиотеки функций и
                функций XPath из раздела 10 в RFC 7950.
              - Узлом контекста служит корневой узел хранилища.";
           reference
             "XML Path Language (XPath) Version 1.0
              (https://www.w3.org/TR/1999/REC-xpath-19991116) 
              RFC 7950: The YANG 1.1 Data Modeling Language,
                        Section 10";
         }
       }
     }

     grouping selection-filter-objects {
       description
         "Определяет селектор для объектов из хранилища.";
       choice selection-filter {
         description
           "Источник фильтра отбора, применяемого для подписки. Это
            может быть (1) ссылка на глобальный список или (2) указание 
            в самой подписке.";
         case by-reference {
           description
             "Фильтр, настроенный отдельно.";
           leaf selection-filter-ref {
             type selection-filter-ref;
             mandatory true;
             description
               "Ссылка на имеющийся фильтр отбора для применения 
                к подписке.";
           }
         }
         case within-subscription {
           description
             "Локальное задание позволяет фильтру иметь жизненный цикл
              как у подписки.";
           uses selection-filter-types;
         }
       }
     }

     grouping update-policy-modifiable {
       description
         "Описывает связанные с хранилищем условия подписки, которые
          можно изменить в течение действия подписки.";
       choice update-trigger {
         description
           "Условия, требуемые для передачи подписчику записи 
            обновления.";
         case periodic {
           container periodic {
             presence "Указывает периодическую подписку";
             description
               "У издателя запрашивается периодическая отправка 
                получателю сведений о текущих значения узлов хранилища,
                определённых фильтром отбора.";
             leaf period {
               type centiseconds;
               mandatory true;
               description
                 "Интервал между периодическими push обновлениями в
                  сотых долях секунды (0,01).";
             }
             leaf anchor-time {
               type yang:date-and-time;
               description
                 "Временная метка, до или после которой задаётся серия
                  периодических обновлений. Следующая отправка будет
                  по истечении целого числа интервалов передачи от
                  anchor-time'. Например, при anchor-time, указывающем 
                  начало определённой минуты, и интервале в 1 минуту 
                  обновления будут передаваться в начале каждой минуты, 
                  когда подписка активна.";
             }
           }
         }
         case on-change {
           if-feature "on-change";
           container on-change {
             presence "Указывает подписку on-change.";
             description
               "У издателя запрошено уведомление получателя при смене
                в хранилище данных значений, заданных фильтром отбора.";
             leaf dampening-period {
               type centiseconds;
               default "0";
               description
                 "Минимальный интервал между сборкой последовательных 
                  записей обновления для одного получателя подписки.
                  Когда объект подписки изменился и истёк интервал
                  демпфирования (возможно, 0) после отправки предыдущей
                  записи обновления получателю, все изменившиеся объекты
                  и свойства подписки упорядочиваются и помещаются в
                  новую запись.";
             }
           }
         }
       }
     }

     grouping update-policy {
       description
         "Зависящие от хранилища условия подписки.";
       uses update-policy-modifiable {
         augment "update-trigger/on-change/on-change" {
           description
             "Объекты, которые нельзя изменить после организации
              подписки.";
           leaf sync-on-start {
             type boolean;
             default "true";
             description
               "Значение false (1) запрещает передавать уведомления
                push-update в подписке on-change и (2) ЗАПРЕЩАЕТ 
                выталкивание полного набора объектов в соответствии 
                с фильтром для этой подписки. Передаются лишь
                уведомления об изменениях (push-change-update). Значение
                true (задано по умолчанию) для упрощения синхронизации
                получателя разрешает передачу полного обновления в
                уведомлении push-update при старте подписки. После этого
                передаются лишь уведомления push-change-update, пока
                издатель не решит ресинхронизировать подписку с помощью
                нового уведомления push-update.";
           }
           leaf-list excluded-change {
             type change-type;
             description
               "Ограничивает набор изменений, вызывающих обновление. 
                Например, при исключении операции replace будут 
                передаваться лишь уведомления о создании и удалении.";
           }
         }
       }
     }

     grouping hints {
       description
         "Параметры, связанные с ошибкой подписки на хранилище данных.";
       leaf period-hint {
         type centiseconds;
         description
           "Возвращается при запросе слишком короткого периода. Этот
            совет может включать приемлемый интервал для периодической
            подписки или время демпфирования для подписки on-change.";
       }
       leaf filter-failure-hint {
         type string;
         description
           "Сведения о причине неприемлемости указанного фильтра 
            для подписки.";
       }
       leaf object-count-estimate {
         type uint32;
         description
           "Если фильтр отбора может возвращать слишком много объектов,
            это значение указывает оценку числа таких объектов.";
       }
       leaf object-count-limit {
         type uint32;
         description
           "Если фильтр отбора возвращает слишком много объектов, это
            значение указывает верхний предел числа таких объектов.";
       }
       leaf kilobytes-estimate {
         type uint32;
         description
           "Если возвращаемая информация может выходить за пределы
            возможностей издателя, это значение будет указывать оценку
            максимального объёма данных после фильтра отбора.";
       }
       leaf kilobytes-limit {
         type uint32;
         description
           "Если возвращаемая информация может выходить за пределы
            возможностей издателя, это значение будет указывать верхний
            предел объёма данных после фильтра отбора.";
       }
     }

     /*
      * RPC
      */
     rpc resync-subscription {
       if-feature "on-change";
       description
         "Позволяет подписчику запросить выталкивание всех объектов
          в активной подписке on-change. Успешный вызов RPC ведёт к
          уведомлению push-update для всех узлов хранилища, к которым
          подписчику разрешён доступ. Этот вызов RPC возможен только
          из той же сессии, в которой работает подписка. В случае 
          ошибки передаётся отклик с resync-subscription-error.";
       input {
         leaf id {
           type sn:subscription-id;
           mandatory true;
           description
             "Идентификатор подписки для ресинхронизации.";
         }
       }
     }

     rc:yang-data resync-subscription-error {
       container resync-subscription-error {
         description
           "При отказе RPC resync-subscription подписка не 
            ресинхронизируется и сообщение об ошибке ДОЛЖНО указывать
            причину отказа. Эта структура yang-data МОЖЕТ включаться в
            отклик об ошибке для указания причины отказа.";
         leaf reason {
           type identityref {
             base resync-subscription-error;
           }
           mandatory true;
           description
             "Указывает причину отклонения запроса ресинхронизации.";
         }
         uses hints;
       }
     }

     augment "/sn:establish-subscription/sn:input" {
       description
         "Добавляет параметры подписки, применяемые к обновлениям
          хранилища данных, как входные параметры RPC.";
       uses update-policy;
     }

     augment "/sn:establish-subscription/sn:input/sn:target" {
       description
         "Добавляет хранилище данных как действительную цель для
          подписки в качестве входных данных RPC.";
       case datastore {
         description
           "Сведения о параметрах запроса для подписки на хранилище.";
         uses datastore-criteria;
       }
     }

     rc:yang-data establish-subscription-datastore-error-info {
       container establish-subscription-datastore-error-info {
         description
           "Если какой-либо параметр RPC establish-subscription не
            поддерживается для хранилища, подписка не организуется
            и отклик об ошибке RPC ДОЛЖЕН указывать причину отказа
            в подписке. Эта структура yang-data МОЖЕТ помещаться в
            отклик об ошибке RPC для указания причины отказа. Эта 
            структура ДОЛЖНА включаться, если подписчику возвращаются
            подсказки.";
         leaf reason {
           type identityref {
             base sn:establish-subscription-error;
           }
           description
             "Причина отказа в подписке на целевое хранилище данных.";
         }
         uses hints;
       }
     }

     augment "/sn:modify-subscription/sn:input" {
       description
         "Дополнительные параметры подписки на обновления хранилища.";
       uses update-policy-modifiable;
     }

     augment "/sn:modify-subscription/sn:input/sn:target" {
       description
         "Добавляет хранилище данных как действительную цель для
          подписки в качестве входных данных RPC.";
       case datastore {
         description
           "Сведения о параметрах запроса для подписки на хранилище.";
         uses datastore-criteria;
       }
     }

     rc:yang-data modify-subscription-datastore-error-info {
       container modify-subscription-datastore-error-info {
         description
           "Эта структура yang-data МОЖЕТ включаться в отклик об ошибке
            RPC при отказе modify-subscription для хранилища данных.
            Структура ДОЛЖНА использоваться, если подписчику 
            возвращаются подсказки.";
         leaf reason {
           type identityref {
             base sn:modify-subscription-error;
           }
           description
             "Причина отказа в изменении подписки.";
         }
         uses hints;
       }
     }

     /*
      * Уведомления
      */
     notification push-update {
       description
         "Уведомление с push-обновлением, с данными для подписки. При
          периодической подписке это уведомление передаётся для
          периодических обновлений. Оно также применяется для 
          синхронизации обновлений в подписке on-change. Это уведомление
          нужно передавать лишь получателям подписки, оно не является
          уведомлением общего назначения, на которое можно подписаться
          любому получателю как на часть потока событий NETCONF.";
       leaf id {
         type sn:subscription-id;
         description
           "Указывает подписку, вызвавшую отправку уведомления.";
       }
       anydata datastore-contents {
         description
           "Обновлённые данные, содержащие снимок на момент обновления
            для всего набора данных подписки. Эти же данные были бы
            возвращены операцией get с таким же фильтром отбора.";
       }
       leaf incomplete-update {
         type empty;
         description
           "Флаг, указывающий неполноту обновления. Иными словами, 
            издатель не смог выполнить все свои обязательства по 
            подписке и передал неполный набор объектов.";
       }
     }

     notification push-change-update {
       if-feature "on-change";
       description
         "Pus-обновление on-change, которое нужно передавать лишь 
          получателям подписки, оно не является уведомлением общего
          назначения, на которое можно подписаться любому получателю
          как на часть потока событий NETCONF.";
       leaf id {
         type sn:subscription-id;
         description
           "Указывает подписку, вызвавшую отправку уведомления.";
       }
       container datastore-changes {
         description
           "Набор изменений целевого хранилища, начиная с момента
            предыдущего обновления по условиям подписки.";
         uses ypatch:yang-patch;
       }
       leaf incomplete-update {
         type empty;
         description
           "Указывает, что включены не все изменения после предыдущего 
            обновления. Иными словами, издатель не смог полностью
            выполнить свои обязательства по подписке, например, по
            причине большого числа произошедших изменений.";
       }
     }

     augment "/sn:subscription-started" {
       description
         "Добавляет связанные с хранилищем объекты в уведомление,
          передаваемое при старте подписки.";
       uses update-policy;

     augment "/sn:subscription-started/sn:target" {
       description
         "Позволяет включать хранилище в уведомление при старте
          подписки.";
       case datastore {
         uses datastore-criteria {
           refine "selection-filter/within-subscription" {
             description
               "Задаёт фильтр отбора и его местоположение. При указании
                selection-filter-ref фильтр берётся из контейнера
                filters, иначе задаётся явно как часть подписки.";
           }
         }
       }
     }

     augment "/sn:subscription-modified" {
       description
         "Добавляет связанные с хранилищем объекты в уведомление при
          изменении подписки.";
       uses update-policy;
     }

     augment "/sn:subscription-modified/sn:target" {
       description
         "Позволяет включать хранилище в уведомление при обновлении
          подписки.";
       case datastore {
         uses datastore-criteria {
           refine "selection-filter/within-subscription" {
             description
               "Задаёт фильтр отбора и его местоположение. При указании
                selection-filter-ref фильтр берётся из контейнера
                filters, иначе задаётся явно как часть подписки.";
           }
         }
       }
     }

     /*
      * Узлы данных
      */
     augment "/sn:filters" {
       description
         "Позволяет включать хранилище как часть критериев отбора
          для подписки.";
       list selection-filter {
         key "filter-id";
         description
           "Список заданных заранее фильтров, применяемых к подписке.";
         leaf filter-id {
           type string;
           description
             "Идентификатор фильтра отбора.";
         }
         uses selection-filter-types;
       }
     }

     augment "/sn:subscriptions/sn:subscription" {
       when 'yp:datastore';
       description
         "Добавляет в подписку на хранилище объекты, связанные с 
          хранилищем, например, поток обновлений узлов хранилища.";
       uses update-policy;
     }

     augment "/sn:subscriptions/sn:subscription/sn:target" {
       description
         "Позволяет включать хранилище как часть критериев отбора
          для подписки.";
       case datastore {
         uses datastore-criteria;
       }
     }
   }
   <CODE ENDS>

6. Взаимодействие с IANA

Этот документ добавляет URI в реестр IETF XML Registry [RFC3688].

   URI: urn:ietf:params:xml:ns:yang:ietf-yang-push
   Registrant Contact: The IESG.
   XML: N/A; запрошенный URI является пространством имён XML.

Документ добавляет модуль YANG в реестр YANG Module Names [RFC6020]

   Name: ietf-yang-push
   Namespace: urn:ietf:params:xml:ns:yang:ietf-yang-push
   Prefix: yp
   Reference: RFC 8641

7. Вопросы безопасности

Описанный в этом документе модуль YANG определяет схему данных, которая предназначения для доступа по протоколам сетевого управления, таким как NETCONF [RFC6241] или RESTCONF [RFC8040]. Нижним уровнем NETCONF является защищённый транспорт с обязательной поддержкой SSH [RFC6242]. Нижним уровнем RESTCONF является HTTPS с обязательной поддержкой TLS [RFC5246].

Модель управления доступом NETCONF (Network Configuration Access Control Model или NACM) [RFC8341] обеспечивает способы ограничения доступа отдельным пользователям NETCONF или RESTCONF заданным подмножеством всех доступных операций и содержимого NETCONF или RESTCONF.

В модуле YANG имеется множество узлов данных, доступных для чтения, создания и удаления (например, с принятым по умолчанию config true). Эти узлы могут быть конфиденциальными или уязвимыми в некоторых сетевых средах. Операции записи (например, <edit-config>) в эти узлы без подобающей защиты могут оказывать негативное влияние на работу сети. Следует отметить, что заданный здесь модель YANG дополняет модуль YANG из [RFC8639] и все соображения безопасности, отмеченные в [RFC8639], применимы и к подпискам на хранилища данных. Ниже перечислены субдеревья и узлы данных, добавленные в этом документе, с указанием уязвимости.

Ветвь selection-filter в контейнере filters

Эта ветвь позволяет подписчику указать узлы и ветви для включения в подписку на хранилище. Атакующий может попытаться изменить этот фильтр, например, для увеличения числа возвращаемых объектов с целью перегрузки получателя. Можно также исключить часть объектов из подписки, делая их изменения незаметными.

Ветвь datastore в выборе target списка subscription

Как и для ветви selection-filter, злоумышленник может пытаться изменить фильтруемые объекты для перегрузки получателя большим числом обновлений или сокрытия некоторых изменений.

Выбор update-trigger в списке subscription

Меняя триггер обновлений, злоумышленник может изменить передаваемые обновления для запутывания получателя или его перегрузки. Например, атакующий может поменять период отправки уведомлений в периодической подписке или интервал демпфирования в подписке on-change, увеличивая задержку передачи обновления, что может влиять на скорость отклика зависящих от обновлений приложений, или увеличивая число обновлений для истощения ресурсов получателя.

NACM обеспечивает средства для смягчения этих угроз на стороне издателя. Для смягчения угроз у получателей тот может отслеживать конфигурацию подписки на предмет неожиданных изменений и подписываться на обновления узлов хранилища данных YANG, представляющих подписку на хранилища. Поскольку объем таких данных невелик, сверхосторожный подписчик может даже сохранить периодический опрос для защиты подписки от скомпрометированных обновлений конфигурации самой подписки.

Некоторые из доступных для чтения узлов в этом модуле YANG могут быть конфиденциальны или уязвимы в той или иной сетевой среде. Важно контролировать доступ к таким объектам (например, get, get-config, notification). Ниже перечислены ветви и узлы, которые могут быть конфиденциальны или уязвимы.

Ветвь selection-filter в контейнере filters

Отсутствие должного контроля доступа может раскрывать компоненты системы для тех, кто не должен видеть их.

Ветвь datastore в выборе target списка subscription

Отсутствие должного контроля доступа может раскрывать компоненты системы для тех, кто не должен видеть их.

Выбор update-trigger в списке subscription

Отсутствие должного контроля доступа может раскрывать компоненты системы для тех, кто не должен видеть их.

Некоторые из операций RPC в этих модулях YANG могут быть чувствительны или уязвимы в той или иной сетевой среде. Важно контролировать доступ к таким операциям. Ниже указзаны операции модуля ieft-dhcpv6-relay.yang, которые могут быть чувствительны или уязвимы.

RPC resync-subscription

Этот вызов RPC позволяет подписчику on-change щапросить выталкивание всех объектов подписки, что может приводить к передаче большого объёма данных. Злоумышленник может попытаться использовать RPC для истощения ресурсов сервера генерацией данных и последующей перегрузки получателя этими данными.

8. Литература

8.1. Нормативные документы

[RFC2119] Bradner, S., «Key words for use in RFCs to Indicate Requirement Levels», BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, <https://www.rfc-editor.org/info/rfc2119>.

[RFC3688] Mealling, M., «The IETF XML Registry», BCP 81, RFC 3688, DOI 10.17487/RFC3688, January 2004, <https://www.rfc-editor.org/info/rfc3688>.

[RFC6020] Bjorklund, M., Ed., «YANG — A Data Modeling Language for the Network Configuration Protocol (NETCONF)», RFC 6020, DOI 10.17487/RFC6020, October 2010, <https://www.rfc-editor.org/info/rfc6020>.

[RFC6991] Schoenwaelder, J., Ed., «Common YANG Data Types», RFC 6991, DOI 10.17487/RFC6991, July 2013, <https://www.rfc-editor.org/info/rfc6991>.

[RFC7950] Bjorklund, M., Ed., «The YANG 1.1 Data Modeling Language», RFC 7950, DOI 10.17487/RFC7950, August 2016, <https://www.rfc-editor.org/info/rfc7950>.

[RFC8040] Bierman, A., Bjorklund, M., and K. Watsen, «RESTCONF Protocol», RFC 8040, DOI 10.17487/RFC8040, January 2017, <https://www.rfc-editor.org/info/rfc8040>.

[RFC8072] Bierman, A., Bjorklund, M., and K. Watsen, «YANG Patch Media Type», RFC 8072, DOI 10.17487/RFC8072, February 2017, <https://www.rfc-editor.org/info/rfc8072>.

[RFC8174] Leiba, B., «Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words», BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017, <https://www.rfc-editor.org/info/rfc8174>.

[RFC8341] Bierman, A. and M. Bjorklund, «Network Configuration Access Control Model», STD 91, RFC 8341, DOI 10.17487/RFC8341, March 2018, <https://www.rfc-editor.org/info/rfc8341>.

[RFC8342] Bjorklund, M., Schoenwaelder, J., Shafer, P., Watsen, K., and R. Wilton, «Network Management Datastore Architecture (NMDA)», RFC 8342, DOI 10.17487/RFC8342, March 2018, <https://www.rfc-editor.org/info/rfc8342>.

[RFC8446] Rescorla, E., «The Transport Layer Security (TLS) Protocol Version 1.3», RFC 8446, DOI 10.17487/RFC8446, August 2018, <https://www.rfc-editor.org/info/rfc8446>.

[RFC8525] Bierman, A., Bjorklund, M., Schoenwaelder, J., Watsen, K., and R. Wilton, «YANG Library», RFC 8525, DOI 10.17487/RFC8525, March 2019, <https://www.rfc-editor.org/info/rfc8525>.

[RFC8639] Voit, E., Clemm, A., Gonzalez Prieto, A., Nilsen-Nygaard, E., and A. Tripathy, «Subscription to YANG Notifications», RFC 8639, DOI 10.17487/RFC8639, September 2019, <https://www.rfc-editor.org/info/rfc8639>.

[W3C.REC-xml-20081126] Bray, T., Paoli, J., Sperberg-McQueen, M., Maler, E., and F. Yergeau, «Extensible Markup Language (XML) 1.0 (Fifth Edition)», World Wide Web Consortium Recommendation REC-xml-20081126, November 2008, <https://www.w3.org/TR/2008/REC-xml-20081126>.

[XPATH] Clark, J. and S. DeRose, «XML Path Language (XPath) Version 1.0», November 1999, <https://www.w3.org/TR/1999/REC-xpath-19991116>.

8.2. Дополнительная литература

[RFC6241] Enns, R., Ed., Bjorklund, M., Ed., Schoenwaelder, J., Ed., and A. Bierman, Ed., «Network Configuration Protocol (NETCONF)», RFC 6241, DOI 10.17487/RFC6241, June 2011, <https://www.rfc-editor.org/info/rfc6241>.

[RFC6242] Wasserman, M., «Using the NETCONF Protocol over Secure Shell (SSH)», RFC 6242, DOI 10.17487/RFC6242, June 2011, <https://www.rfc-editor.org/info/rfc6242>.

[RFC7923] Voit, E., Clemm, A., and A. Gonzalez Prieto, «Requirements for Subscription to YANG Datastores», RFC 7923, DOI 10.17487/RFC7923, June 2016, <https://www.rfc-editor.org/info/rfc7923>.

[RFC8340] Bjorklund, M. and L. Berger, Ed., «YANG Tree Diagrams», BCP 215, RFC 8340, DOI 10.17487/RFC8340, March 2018, <https://www.rfc-editor.org/info/rfc8340>.

[RFC8343] Bjorklund, M., «A YANG Data Model for Interface Management», RFC 8343, DOI 10.17487/RFC8343, March 2018, <https://www.rfc-editor.org/info/rfc8343>.

[RFC8640] Voit, E., Clemm, A., Gonzalez Prieto, A., Nilsen-Nygaard, E., and A. Tripathy, «Dynamic Subscription to YANG Events and Datastores over NETCONF», RFC 8640, DOI 10.17487/RFC8640, September 2019, <https://www.rfc-editor.org/info/rfc8640>.

[Yang-Push-Notif-Cap] Lengyel, B., Clemm, A., and B. Claise, «Yang-Push Notification Capabilities», Work in Progress4, draft-ietf-netconf-notification-capabilities-04, September 2019.

Приложение A. Ошибки при подписке

A.1. Отказы RPC

Отклонение RPC по любой причине указывается откликом об ошибке RPC от издателя. Возвращаемые ошибки RPC включают (1) имеющиеся коды ошибок RPC на транспортном уровне, такие как приведены для NETCONF в [RFC6241], и (2) связанные с подпиской ошибки, заданные в модели данных YANG. В результате кодирование ошибок в откликах RPC зависит от транспорта.

Конкретные идентификаторы из модулей YANG ietf-subscribed-notifications [RFC8639] и ietf-yang-push могут возвращаться как часть сообщений об ошибках при неудачных попытках подписки на хранилища данных. Ошибки из модуля ietf-subscribed-notifications указаны в [RFC8639], а ошибки, определённые этим документом, приведены ниже.

 

establish-subscription

modify-subscription

resync-subscription

cant-exclude

period-unsupported

no-such-subscription-resync

datastore-not-subscribable

update-too-big

sync-too-big

on-change-unsupported

sync-too-big

on-change-sync-unsupported

unchanging-selection

period-unsupported

update-too-big

sync-too-big

unchanging-selection

 

В модель данных YANG включён финальный набор элементов для независимых от транспорта ошибок RPC в 4 структурах yang-data для отказов при подписке на хранилища данных.

  1. Структура yang-data establish-subscription-error-datastore должна возвращаться, если сведения о причине ошибки RPC не включены в транспортную часть отклика об ошибке RPC establish-subscription. Она должна передаваться, если включены подсказки.

  2. Структура yang-data modify-subscription-error-datastore должна возвращаться, если сведения о причине ошибки RPC не включены в транспортную часть отклика об ошибке RPC modify-subscription. Она должна передаваться, если включены подсказки.

  3. Структура yang-data sn:delete-subscription-error должна возвращаться, если сведения о причине ошибки RPC не включены в транспортную часть отклика об ошибке RPC delete-subscription или kill-subscription.

  4. Структура yang-data resync-subscription-error должна возвращаться, если сведения о причине ошибки RPC не включены в транспортную часть отклика об ошибке RPC resync-subscription.

A.2. Уведомления об отказах

Подписка может быть неожиданно прервана или приостановлена без вызова RPC или операции настройки. В таких случаях должна указываться причина отказа. Может возвращаться ряд ошибок в соответствующем уведомлении о смене состояния подписки. Для этого документ вводит указанные ниже идентификаторы ошибок, дополняющие ошибки, заданные в [RFC8639].

 

subscription-terminated

subscription-suspended

datastore-not-subscribable

period-unsupported

unchanging-selection

update-too-big

synchronization-size

 

Благодарности

Спасибо Tim Jenkins, Martin Bjorklund, Kent Watsen, Susan Hares, Yang Geng, Peipei Guo, Michael Scharf, Guangying Zheng, Tom Petch, Henk Birkholz, Reshad Rahman, Qin Wu, Rohit Ranade, Rob Wilton за ценные комментарии, дискуссии и отзывы.

Участники работы

Ниже указаны люди, внёсшие существенные вклад в этот документ, которых следует считать соавторами. Их вклад состоит в создании модуля YANG, представленного в разделе 5.

Alberto Gonzalez Prieto
Microsoft
Email: alberto.gonzalez@microsoft.com
 
Ambika Prasad Tripathy
Cisco Systems
Email: ambtripa@cisco.com
 
Einar Nilsen-Nygaard
Cisco Systems
Email: einarnn@cisco.com
 
Andy Bierman
YumaWorks
Email: andy@yumaworks.com
 
Balazs Lengyel
Ericsson
Email: balazs.lengyel@ericsson.com

Адреса авторов

Alexander Clemm
Futurewei
Email: ludwig@clemm.org
 
Eric Voit
Cisco Systems
Email: evoit@cisco.com

Перевод на русский язык

Николай Малых

nmalykh@protokols.ru

1Internet Engineering Task Force — комиссия по решению инженерных задач Internet.

2Internet Engineering Steering Group — комиссия по инженерным разработкам Internet.

3XPath — это язык запросов для выбора узлов в документе XML [XPATH].

4Опубликовано в RFC 9196. Прим. перев.

Рубрика: RFC | Оставить комментарий