Теоретические основы и архитектура
Современное управление сетью оператора опирается на программные интерфейсы (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-платформе:
<!-- 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-interfacesRFC 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.