Теоретические основы и архитектура

Современное управление сетью оператора опирается на программные интерфейсы (API) вместо ручного ввода команд в CLI и разбора текстового вывода (screen scraping). Для этого применяются NETCONF (RFC 6241) и gNMI (gRPC Network Management Interface). 1. NETCONF работает поверх SSH (порт 830 по IANA, RFC 6242) и передаёт XML-сообщения RPC: <get-config>, <edit-config>, <lock>, <validate>, <commit>, <discard-changes>. Транзакционность зависит от capabilities устройства: на платформах с datastore candidate изменения накапливаются и применяются <commit> (а <commit><confirmed/> откатывает их по таймеру), а при :writable-running без :rollback-on-error часть изменений может остаться применённой. Утверждение, что маршрутизатор «всегда откатывает сам», неверно. 2. Моделирование данных: и NETCONF, и gNMI используют язык YANG (RFC 7950 для версии 1.1). Модели бывают стандартные (IETF, OpenConfig) и вендорские (native); конфигурацию PE обычно пишут по native-модели проверенной платформы, а состояние читают по OpenConfig. 3. gNMI разработан сообществом OpenConfig на базе gRPC/HTTP/2 с кодированием Protocol Buffers и включает RPC Capabilities, Get, Set и Subscribe. Set применяется как одна транзакция (всё или ничего), Subscribe даёт потоковую телеметрию; IANA зарегистрировала для gNMI порт 9339, но на практике встречаются и вендорские порты, поэтому порт берут из конфигурации устройства.

Что стандартизовано, а что нет

Программируемый интерфейс состоит из трёх независимых слоёв: транспорт (SSH или HTTP/2 с TLS), протокол операций (NETCONF RPC или gNMI RPC) и модель данных на языке YANG. Менять можно каждый слой отдельно: одна и та же YANG-модель отдаётся и по NETCONF, и по gNMI, а один и тот же NETCONF работает с моделями разных вендоров. Это важно для L3VPN: транспорт и операции переносимы, а вот содержимое (дерево VRF, RD, RT, BGP vpnv4) у Cisco, Huawei и Juniper выглядит по-разному, пока вы работаете с native-моделями.

NETCONF: сессия, capabilities, datastores

NETCONF (RFC 6241) идёт как подсистема SSH. Порт 830 назначен IANA для netconf-ssh (RFC 6242), а многие платформы дополнительно принимают подсистему netconf на порту 22. После установления SSH каждая сторона отправляет <hello> со списком capabilities и версией base: urn:ietf:params:netconf:base:1.0 или base:1.1. Если обе стороны поддерживают 1.1, включается chunked framing; в 1.0 сообщения разделяет последовательность ]]>]]>. Именно поэтому самописные клиенты на голом сокете ломаются, а ncclient, Netconf-клиенты в Ansible и scrapli-netconf работают.

Capabilities определяют, что можно делать с устройством:

  • :candidate - есть отдельный candidate datastore; изменения накапливаются и применяются операцией <commit>.
  • :writable-running - <edit-config> разрешён прямо в running; commit не нужен, и каждая операция применяется немедленно.
  • :confirmed-commit - <commit><confirmed/> с таймаутом (по умолчанию 600 секунд): если за это время не пришёл второй <commit>, устройство откатывается само.
  • :validate - операция <validate> проверяет candidate без применения.
  • :rollback-on-error - при ошибке в одном элементе <edit-config> откатывается весь запрос.
  • :startup, :xpath, :url - startup datastore, XPath-фильтры, конфигурация из URL.

Cisco IOS-XE по умолчанию отдаёт только running, а candidate включается командой netconf-yang feature candidate-datastore (после этого конфигурация через CLI блокируется до отключения функции). Junos работает с candidate всегда. На Huawei VRP набор определяется версией ПО; смотрите capabilities в <hello>, а не документацию.

Операции и семантика edit-config

  • <get> читает конфигурацию и operational state, <get-config> только конфигурацию выбранного datastore. Фильтр задаётся subtree-способом или XPath.
  • <edit-config> изменяет datastore. Атрибут operation у элемента принимает merge (по умолчанию), replace, create (ошибка, если уже есть), delete (ошибка, если нет) и remove (без ошибки). Элемент default-operation задаёт поведение для всего запроса. Классическая ошибка - replace на контейнере верхнего уровня: он удалит всех соседей, которых вы не перечислили.
  • <lock>/<unlock> блокируют datastore на время транзакции; чужая сессия получит lock-denied. <kill-session> снимает зависшую сессию.
  • <validate>, <commit>, <discard-changes> работают с candidate. <copy-config> и <delete-config> оперируют целыми datastore.

Атомарность задана не всегда. <edit-config> атомарен относительно одного запроса, если есть :rollback-on-error или сам candidate-commit откатывает неудачу. Утверждение, что маршрутизатор "всегда откатывает сам", неверно: при :writable-running без rollback-on-error половина изменений остаётся.

Минимальный безопасный цикл на candidate-платформе:

xml
<!-- lock, edit candidate, validate, confirmed commit, final commit -->
<lock><target><candidate/></target></lock>
<edit-config><target><candidate/></target><config>...</config></edit-config>
<validate><source><candidate/></source></validate>
<commit><confirmed/><confirm-timeout>120</confirm-timeout></commit>
<commit/>
<unlock><target><candidate/></target></unlock>

Если после confirmed commit пропала связь с контроллером, финальный <commit> не придёт, и через 120 секунд PE вернёт прежнюю конфигурацию.

YANG: native, IETF, OpenConfig

YANG (RFC 7950 для версии 1.1, RFC 6020 для 1.0) описывает дерево из container, list с ключами, leaf, leaf-list, choice, типов, must/when-ограничений и identity. Модуль версионируется ревизией (revision 2023-07-01), расширяется через augment и подправляется вендором через deviation. Три семейства моделей:

  • Native (Cisco-IOS-XE-native, huawei-*, junos-conf-root) повторяют CLI вендора, покрывают всё, но не переносятся между платформами.
  • IETF (ietf-interfaces RFC 8343, ietf-routing, ietf-bgp) стандартизованы, но покрытие у вендоров частичное.
  • OpenConfig (openconfig-interfaces, openconfig-network-instance, openconfig-bgp) пишут операторы. VRF и L3VPN описываются в network-instance с типом L3VRF, RD лежит в config/route-distinguisher, а RT задаются через inter-instance-policies и политики импорта. Покрытие L3VPN у вендоров неравномерно, поэтому для PE чаще используют native-модель и OpenConfig только для телеметрии (интерфейсы, BGP-соседи).

Правило практики: конфигурацию PE пишите по native-модели той платформы, которую вы проверили, а состояние читайте по OpenConfig.