Привет, Хабр! Меня зовут Сергей Балдаков — я техлид группы поддержки сетей передачи данных в компании К2Тех.

В своей практике я часто сталкиваюсь с кейсами, когда в GUI все выглядит красиво:  графики строятся, трафик ходит, коммутаторы жужжат  и греют воздух дата-центра. А вот конкретные сетевые взаимодействия, для которых «вот только вчера сделали контрактик», почему-то не работают. Классическая ситуация — рисовали на бумаге, но забыли про овраги.

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

Надеюсь, этот материал поможет инженерам, работающим с фабриками ACI, разобраться, что же конкретно работает не так в их среде и как настроить работу контрактов правильно.

Способ первый: самый простой — проверка через GUI

Первое, что можно сделать  — это проверить прохождение трафика через инструмент Visibility & Troubleshooting

Он доступен из меню Operations -> Visibility & Troubleshooting и позволяет, не выполняя дополнительных телодвижений, крупными мазками показать ,  пройдет трафик между определенными Endpoint или нет.

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

Определяем вид трафика, который нас интересует:

Endpoint - Endpoint —  тот случай, когда оба хоста зарегистрированы на ACI и изучены в COOP. Можно указывать, как IP (если мы знаем как L3 EP), так и mac адрес. В этом случае GUI автоматически предложит изученную машину для выбора, по ней нужно только кликнуть.

Endpoint - External IP (or vice versa) — когда мы проверяем взаимодействие хоста внутри ACI с внешним миром (например, через L3 Out). Для параметра External IP доступно только указание IP адреса, подсказок со стороны GUI не будет, так как ACI не знает про данный EP.

External IP - External IP — ситуация, когда мы проверяем прохождение транзитного трафика. Мне в реальной жизни с подобным  кейсом работать не приходилось, но, тем не менее, такая возможность есть.

Окно Time Window — можно отобразить информацию за последний период 5-240 минут, либо использовать фиксированный отрезок времени, отметив чекбокс Fixed Time.

Мы рассмотрим на наиболее  репрезентативном примере н проверку связности между двумя EP, находящимися на самой фабрике. 

После нажатия кнопки Submit ACI выводит схему, по которой проходит трафик между двумя EP внутри фабрики, а также подсвечивает ошибки на Leaf/Spine коммутаторах, если таковые имеются в данном взаимодействии.

Сразу прошу извинить, что IP будут приведены в такой неудобной форме, увы - требования ИБ 
Сразу прошу извинить, что IP будут приведены в такой неудобной форме, увы - требования ИБ 

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

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

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

Однако этот  инструмент не даст ответа на вопрос, если связность между EP есть, но, например,  соединение по 22 порту не устанавливается.

Для более детальной диагностики используем следующий инструмент.

Способ второй: fTriage

fTriage использует в своей работе данные ELAM с коммутаторов, из которых состоит фабрика.

Для работы ему необходимо задать несколько параметров, в зависимости от типа трафика, который мы проверяем. После получения данных параметров fTriage инициирует создание ELAM триггера на Leaf коммутаторах, которые мы указали как стартовую точку для поиска трафика. После чего считывает информацию из ELAM, передает её в Human readeble формате в вывод на APIC. Инициирует ELAM триггер на следующем коммутаторе, который он определяет по выводу предыдущего ELAM. И по такой цепочке до того момента, пока пакет не достигнет своей конечной точки на фабрике — порта в сторону EP или порта в сторону L3Out.

Исходя из вышесказанного следует, что для работы ELAM триггеров данному инструменту требуется присутствие «живого» трафика  как вариант постоянных ICMP запросов. Например, так:

Однако поскольку  пример рассматривает проблемы на 22 порту, то нам понадобится простой скрипт на python, который мы запустим на машине-инициаторе трафика. Если по какой-то причине такой скрипт запустить невозможно, то потребуется вручную отправить несколько запросов на 22 порт хоста назначения.

Пример скрипта

import socket

import time

def check_port(ip, port, timeout=5):

    while True:

        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        sock.settimeout(timeout)

        try:

            sock.connect((ip, port))

            print(f"Соединение с {ip}:{port} успешно установлено.")       

            sock.close()

            time.sleep(5)

        except socket.timeout:

            print(f"Ошибка тайм-аута при соединении с {ip}:{port}. Повторная попытка через 5 секунд.")

            time.sleep(5)

        except socket.error as e:

            print(f"Не удалось соединиться с {ip}:{port}. Ошибка: {e}")

            time.sleep(5)

        finally:

            sock.close()

ip_address = "X.X.10.179"  

port = 22

check_port(ip_address, port)

fTriage вызывается из CLI интерфейса APIC сервера

По данному инструменту можно посмотреть встроенную справку на APIC:

ftriage example - примеры использования команды;

ftriage -h - вывод общего help;

ftriage <команда> -h вывод help по конкретной команде (например ftriage route -h).

В примере, который мы рассматриваем в этой  статье, нам нужен тип трафика route, так как данный пакет маршрутизируется внутри фабрики, а не коммуницирует в рамках одного bridge domain

Запустим на тестовой машине наш скрипт, чтобы сгенерировать поток трафика:

На APIC сервере запускаем ftriage со следующими параметрами, чтобы проследить за тем, что происходит с пакетом:

ftriage -user username route (так как трафик L3) -ii VPC:VPC_TEST-SEGMENT (интерфейс на котором ожидаем входящий трафик) -sip X.X.16.5 (source ip в заголовке) -dip X.X.10.179 (destination ip в заголовке)

После выполнения команды получаем следующий вывод:

TEST-APIC-01# ftriage -user admin route -ii VPC:VPC_TEST-SEGMENT -sip X.X.16.5 -dip X.X.10.179

Starting ftriage

Log file name for the current run is: ftlog_2025-08-04-14-01-25-455.txt

2025-08-04 14:01:25,460 INFO     /controller/bin/ftriage -user admin route -ii VPC:VPC_TEST-SEGMENT -sip X.X.16.5 -dip X.X.10.179

Request password info for username: admin

Password:

2025-08-04 14:01:46,724 INFO     ftriage:      pif:103  VPC VPC_TEST-SEGMENT maps to N9K-TEST-Leaf-16:Po2,N9K-TEST-Leaf-15:Po1

2025-08-04 14:02:34,662 INFO     ftriage:     main:2064 Invoking ftriage with username: admin

2025-08-04 14:02:54,403 INFO     ftriage:     main:1491 Enable Async parellel ELAM with 2 nodes

2025-08-04 14:03:03,248 INFO     ftriage:     fcls:2371 N9K-TEST-Leaf-16: Valid ELAM for asic:0 slice:0 srcid:84 pktid:1080

2025-08-04 14:03:03,941 INFO     ftriage:     fcls:2658 N9K-TEST-Leaf-16: Signal ELAM found for Async lookup

2025-08-04 14:03:03,944 ERROR    ftriage:  unicast:238  N9K-TEST-Leaf-16: L3 packet getting fwd dropped, checking drop reason

2025-08-04 14:03:03,944 ERROR    ftriage:  unicast:238  N9K-TEST-Leaf-16: L3 packet getting fwd dropped, checking drop reason

0x00000000000400000              condition setcast:240  N9K-TEST-Leaf-16: Drop reason - SECURITY_GROUP_DENY              condition set

2025-08-04 14:03:13,031 INFO     ftriage:  unicast:265  N9K-TEST-Leaf-16: policy drop flow sclass:32874 dclass:16410 sg_label:4 proto:6

2025-08-04 14:03:13,031 INFO     ftriage:  unicast:287  N9K-TEST-Leaf-16: nxos matching rule id:5950

2025-08-04 14:03:13,032 INFO     ftriage:     main:1523 : Ftriage Completed with hunch: Packet drop

В нем видно, что наш трафик попадает в явное запрещающее правило:

2025-08-04 14:03:03,944 ERROR    ftriage:  unicast:238  N9K-TEST-Leaf-16: L3 packet getting fwd dropped, checking drop reason

0x00000000000400000              condition setcast:240  N9K-TEST-Leaf-16: Drop reason - SECURITY_GROUP_DENY              condition set

2025-08-04 14:03:13,031 INFO     ftriage:  unicast:265  N9K-TEST-Leaf-16: policy drop flow sclass:32874 dclass:16410 sg_label:4 proto:6

2025-08-04 14:03:13,031 INFO     ftriage:  unicast:287  N9K-TEST-Leaf-16: nxos matching rule id:5950

2025-08-04 14:03:13,032 INFO     ftriage:     main:1523 : Ftriage Completed with hunch: Packet drop

sclass 32874 это pcTag source EPG, dclass 16410 это pcTag destination EPG, nxos matching rule 5950 — это ID правила, в которое попадает наш трафик.

Проверить, что же это за правила такие, можно с помощью следующих команд на Leaf коммутаторе.

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

N9K-TEST-Leaf-16# show zoning-rule src-epg 32874 dst-epg 16410

+---------+--------+--------+----------+--------+---------+---------+-------------------------

| Rule ID | SrcEPG | DstEPG | FilterID |  Dir   |  operSt |  Scope  |            Name           | Action |    Priority   |

+---------+--------+--------+----------+--------+---------+---------+-------------------------

|   5950  | 32874  | 16410  |    1     | bi-dir | enabled | 2326528 |     TEST_Tenant:VLAN616    |  deny  | fully_qual(7) |

|   5149  | 32874  | 16410  |    9     | bi-dir | enabled | 2326528 | TEST_Tenant:Default_Permit | permit | fully_qual(7) |

+---------+--------+--------+----------+--------+---------+---------+-------------------------

В случае, когда контрактов много, можно посмотреть сразу по rule-id:

N9K-TEST-Leaf-16# show zoning-rule rule-id 5950

Config State

============

+---------+--------+--------+----------+--------+---------+---------+--------------------+---

| Rule ID | SrcEPG | DstEPG | FilterID |  Dir   |  operSt |  Scope  |        Name        | Action |    Priority   |  Intent |

+---------+--------+--------+----------+--------+---------+---------+--------------------+---

|   5950  | 32874  | 16410  |    1     | bi-dir | enabled | 2326528 | TEST_Tenant:VLAN616 |  deny  | fully_qual(7) | install |

+---------+--------+--------+----------+--------+---------+---------+--------------------+---

Install State

=============

+---------+--------+--------+----------+--------+---------+--------------------+--------+----

| Rule ID | SrcEPG | DstEPG | FilterID |  Dir   |  Scope  |        Name        | Action |    Priority   |

+---------+--------+--------+----------+--------+---------+--------------------+--------+----

|   5950  | 32874  | 16410  |    1     | bi-dir | 2326528 | TEST_Tenant:VLAN616 |  deny  | fully_qual(7) |

+---------+--------+--------+----------+--------+---------+--------------------+--------+----

В этих выводах мы видим, что какой-то нехороший человек намеренно запретил из нашей EPG подключения на 22 порт EPG серверного сегмента.

Осталось только зайти в GUI APIC и удалить ненужный контракт.

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

3. ELAM — Ereport

В этом разделе мы рассмотрим детальный разбор захвата пакета через ELAM и его расшифровку через Ereport.

ELAM расшифровывается как Embedded Logic Analyzer Module. Он предназначен для захвата пакетов на уровне ASIC и позволяет подробно изучить как их заголовки, так и то, как он будет обработан логикой самого коммутатора.

Этот инструмент в ACI унаследован из классической NXOS.

Суть практически аналогична работе ftriage, за тем исключением, что мы подробно разбираем пакет, который активировал триггер ELAM на нашем порту. Ftriage же вынимает из ELAM только самую базовую информацию.

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

Как пример: заказчик утверждает, что в его окружении коммуникация внутри vrf ограничена из-за отсутствия явного разрешающего контракта. Такого контракта между EP нет, но трафик все равно проходит.

Сервер X.X.10.179 доступен по 22 порту с машины X.X.16.5, хотя правила, разрешающего такое взаимодействие, нет.

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

Коммутатор мы выбираем тот, к которому подключена машина – инициатор трафика. В большинстве случае на ACI политики применяются на Ingress интерфейсах.

Переходим в shell линейной карты:

vsh_lc

Включаем дебаг для ASIC:

debug platform internal roc elam asic 0

Тип ASIC зависит от модели коммутатора. Общая логика такая:

N9K-C*-EX- Leaf - ASIC tah 

N9K-C*FX/FXP/FX2 -Leaf - ASIC roc 

N9K-C*-GX – Leaf - ASIC app

Сбрасываем триггер

trigger reset 

Выбираем параметры для необходимого нам трафика. В нашем случае, если мы ожидаем non-VXLAN кадр (так как, по сути, дела мы инициируем триггер на порту в сторону EP), нужно выбрать in-select 6:

trigger init in-select 6 out-select 1

Задаем параметры пакета, который мы ожидаем увидеть:

set outer ipv4 src_ip X.X.16.5 dst_ip X.X.10.179

Стартуем наш ELAM:

start

Запускаем скрипт на тестовой машине и проверяем статус нашего триггера.

status

Если триггер успешно отработал, вбиваем команду: 

ereport

И получаем полный отчет о том, что за пакет к нам пришел, как он будет обработан и куда отправлен (если будет):

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

Первое — это то, что пакет собственно тот, который нас интересует. То есть источник X.X.16.5, назначение X.X.10.179, и порт назначения - 22:

-------------------------------------------------------------------------------------------------

Outer L3 Header

-------------------------------------------------------------------------------------------------

L3 Type                       : IPv4

IP Version                    : 4

DSCP                          : 0

IP Packet Length              : 52 ( = IP header(28 bytes) + IP payload )

Don't Fragment Bit            : set

TTL                           : 128

IP Protocol Number            : TCP

IP CheckSum                   : 50511( 0xC54F )

Destination IP                : X.X.10.179

Source IP                     : X.X.16.5

-------------------------------------------------------------------------------------------------

Outer L4 Header

-------------------------------------------------------------------------------------------------

L4 Type                       : TCP

Source Port                   : 20643( 0x50A3 )

Destination Port              : 22( 0x16 )

TCP/UDP CheckSum              : 0x91F0( 0x91F0 )

Далее мы листаем вывод до секции Contract lookup:

===============================================================================

                                                              Contract Lookup ( FPC )

===============================================================================

-------------------------------------------------------------------------------------------------

Contract Lookup Key

-------------------------------------------------------------------------------------------------

IP Protocol                             : TCP( 0x6 )

L4 Src Port                             : 20643( 0x50A3 )

L4 Dst Port                             : 22( 0x16 )

sclass (src pcTag)                      : 32874( 0x806A )

dclass (dst pcTag)                      : 16410( 0x401A )

src pcTag is from local table           : yes

derived from a local table on this node by the lookup of src IP or MAC

Unknown Unicast / Flood Packet          : no

If yes, Contract is not applied here because it is flooded

-------------------------------------------------------------------------------------------------

Contract Result

-------------------------------------------------------------------------------------------------

Contract Drop                           : no

Contract Logging                        : no

Contract Applied                        : yes

Contract Hit                            : yes

Contract Aclqos Stats Index             : 80827

( show sys int aclqos zoning-rules | grep -B 9 "Idx: 80827" )

В выводе мы обращаем информацию на то, что контракт был все же применен при этом взаимодействии:

Contract Applied                        : yes

Contract Hit                            : yes

Далее прямо в elam, из приглашения module-1(DBG-elam-insel6)#, вводим команду из короткой подсказки в ereport:

show sys int aclqos zoning-rules | grep -B 9 "Idx: 80827"

Этой командой мы смотрим, какую запись в TCAM использовал пакет для обработки:

module-1(DBG-elam-insel6)# show sys int aclqos zoning-rules | grep -B 9 "Idx: 80827"

===========================================

Rule ID: 5950 Scope 4 Src EPG: 32874 Dst EPG: 16410 Filter 9

    unit_id: 0

    === Region priority: 1950 (rule prio: 7 entry: 158)===

        sw_index = 1105 | hw_index = 1093 | stats_idx = 80827

  Curr TCAM resource:

  =============================

    === SDK Info ===

        Result/Stats Idx: 80827

Тут нас интересует параметр Rule ID, который мы можем проверить уже из обычного shell нашего коммутатора.

N9K-TEST-Leaf-16# show zoning-rule rule-id 5950

Config State

============

+---------+--------+--------+----------+----------------+---------+---------+--------------------+--------+-------------

| Rule ID | SrcEPG | DstEPG | FilterID |      Dir       |  operSt |  Scope  |        Name        | Action |    Priority   |  Intent |

+---------+--------+--------+----------+----------------+---------+---------+--------------------+--------+-------------

|   5950  | 32874  | 16410  |    6     | uni-dir-ignore | enabled | 2326528 | TEST_Tenant:VLAN616 | permit | fully_qual(7) | install |

+---------+--------+--------+----------+----------------+---------+---------+--------------------+--------+-------------

Install State

=============

+---------+--------+--------+----------+----------------+---------+--------------------+--------+---------------+

| Rule ID | SrcEPG | DstEPG | FilterID |      Dir       |  Scope  |        Name        | Action |    Priority   |

+---------+--------+--------+----------+----------------+---------+--------------------+--------+---------------+

|   5950  | 32874  | 16410  |    6     | uni-dir-ignore | 2326528 | TEST_Tenant:VLAN616 | permit | fully_qual(7) |

+---------+--------+--------+----------+----------------+---------+--------------------+--------+---------------+

Здесь мы видим, что трафик попадает в правило c направлением uni-dir-ignore. Это говорит нам о том, что трафик попадает в правило для обратного трафика.

Возникает ситуация, когда в контракте создается фильтр с параметрами Apply Both Directions и чекбоксом Reverse filter ports. Поскольку ACI полагается на hardware в виде коммутаторов Nexus, здесь не применимы stateful правила, к которым уже многих приучили фаерволы. А используется решение, когда для обратного трафика программируются отдельные записи в TCAM коммутаторов.

Далее мы ищем в GUI APIC контракт, в который попадает данный трафик, и смотрим его настройки. В частности, настройки фильтров. И где он применен.

Смотрим, что же в этих фильтрах:

Видим, что трафик разрешен с диапазона портов куда угодно.

Теперь проверяем, как же применен контракт.

Видим, что изначальный план был в том, чтобы разрешить коммуникацию с любого порта EPG-Vlan505 до группы портов в EPG Vlan616. Но не было предусмотрено, что обратный трафик так же пойдет по контракту с опциями Apply both Directions и Reverse Filter ports.

Отчасти именно поэтому вендор не рекомендует использовать контракты на ACI с группами портов, так как это может приводить к подобным ситуациям и истощать TCAM коммутаторов из-за особенностей программирования диапазонов портов в нем. 

Заключение

Вот такими инструментами пользуемся мы в нашей рутине в К2Тех. Будет интересно послушать мнение коллег в комментариях. Возможно, есть какие-то способы, которые мы ещё не применяем в своей практике. Конечно, функционал описанных мной инструментов выходит далеко за рамки проверки контрактов на фабрике. Я их рассмотрел, ограничив наш кейс контрактами для простоты восприятия. Поэтому я с удовольствием отвечу на вопросы,  возникшие в результате прочтения.

Комментарии (5)


  1. deny_si
    12.09.2025 08:25

    Эх, ностальгия по давно ушедшей эпохе.


    1. SBaldakov Автор
      12.09.2025 08:25

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


      1. deny_si
        12.09.2025 08:25

        Дело даже не в регуляторе, а в доступе к саппорту вендора. Если такового нет, то эксплуатация подобных решений - боль. И еще, данное решение не предназначено для крупных дата-центров. Только enterprise. В силу определенных архитектурных ограничений.


        1. SBaldakov Автор
          12.09.2025 08:25

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

          На моей практике не встречалось проблем, которые невозможно было решить, даже после 22 года. Единственное что в этом случае можно посоветовать, прежде чем накатывать свежий релиз, дать ему пару месяцев настояться и посмотреть, какие known issues появились у Cisco по нему, потому что day 0 баги, это всегда больно, есть вендор или нет.

          По поводу ограничений для дата-центров очень интересно послушать. Как мне кажется, концепция Tenant'ов разрабатывалась именно для таких решений.


          1. deny_si
            12.09.2025 08:25

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

            Да, только с такими "партнерами" в РФ сейчас сложновато. Опять же, если у партнера нет доступа к вендорскому сервису, "боль" просто переходит от конечника к нему.

            По поводу ограничений для дата-центров очень интересно послушать. Как мне кажется, концепция Tenant'ов разрабатывалась именно для таких решений.

            Вот, например, архитектура базы хранения ендпоинтов в ACI реализована по централизованному принципу. Следовательно, горизонтальное масштабирование затруднено. Отсюда и эти цифры в гайдах по максимальному кол-ву ендпоинтов в системе. Думаю, ЦОД гиперскейлера на такой архитектуре не построить.

            Что у ACI действительно классно сделано, так это management plane с подходом API-first и объектной моделью. А вот control- и data-plane вызывают вопросы.