NETCONF¶
Если вам по какой-то причине кажется, что стандарты рождаются где-то в недрах институтов, оторванных от жизни, то вот вам контр-пример.
| display xml
, то увидите ответ в формате XMLeucariot@kzn-spine-0> show system uptime | display xml <rpc-reply xmlns:junos="http://xml.juniper.net/junos/18.3R3/junos"> <multi-routing-engine-results> <multi-routing-engine-item> <re-name>localre</re-name> <system-uptime-information xmlns="http://xml.juniper.net/junos/18.3R3/junos"> <current-time> <date-time junos:seconds="1641211199">2022-01-03 14:59:59 MSK</date-time> </current-time> <time-source> LOCAL CLOCK </time-source> <system-booted-time> <date-time junos:seconds="1614866046">2021-03-04 16:54:06 MSK</date-time> <time-length junos:seconds="26345153">43w3d 22:05</time-length> </system-booted-time> <protocols-started-time> <date-time junos:seconds="1614866101">2021-03-04 16:55:01 MSK</date-time> <time-length junos:seconds="26345098">43w3d 22:04</time-length> </protocols-started-time> <last-configured-time> <date-time junos:seconds="1638893962">2021-12-07 19:19:22 MSK</date-time> <time-length junos:seconds="2317237">3w5d 19:40</time-length> <user>scamp</user> </last-configured-time> <uptime-information> <date-time junos:seconds="1641211200">3:00PM</date-time> <up-time junos:seconds="26345160">304 days, 22:06</up-time> <active-user-count junos:format="1 users">1</active-user-count> <load-average-1>0.20</load-average-1> <load-average-5>0.17</load-average-5> <load-average-15>0.20</load-average-15> <user-table></user-table> </uptime-information> </system-uptime-information> </multi-routing-engine-item> </multi-routing-engine-results> <cli> <banner>{master:0}</banner> </cli> </rpc-reply>
В корне вы можете видеть <rpc-reply>
, что означает, что был какой-то <rpc>
-request. И вот так вы можете увидеть, каким RPC-запросом можно получить такие данные:
eucariot@kzn-spine-0> show version | display xml rpc <rpc-reply xmlns:junos="http://xml.juniper.net/junos/18.3R3/junos"> <rpc> <get-software-information> </get-software-information> </rpc> <cli> <banner>{master:0}</banner> </cli> </rpc-reply> *Внимание, работает только для Juniper!*
Так вот, их CLI и способ взаимодействия его с системой оказался настолько естественным и удачным, что его и положили в основу стандарта. Не без участия Juniper Networks, конечно же, появился RFC4741. Будем честны, один только джунипер там и постарался. И то тут, то там будут проскакивать его куски, начиная с commit confirmed
и заканчивая candidate config
.
Вот как NETCONF был определён в 2006-м году:
Abstract The Network Configuration Protocol (NETCONF) defined in this document provides mechanisms to install, manipulate, and delete the configuration of network devices. It uses an Extensible Markup Language (XML)-based data encoding for the configuration data as well as the protocol messages. The NETCONF protocol operations are realized on top of a simple Remote Procedure Call (RPC) layer.
И определение с тех пор не менялось - вся суть NETCONF в этом параграфе.
А теперь давайте разбираться с очень непростым NETCONF и его составными частями.
NETCONF и его команды¶
Если совсем коротко, NETCONF - это четырёхуровневый стек, согласно которому через SSH передаётся RPC, где указана операция и конкретный набор действий (контент).
Стек NETCONF¶
Итак, в качестве транспорта NETCONF использует SSH. На самом деле, там есть и другие протоколы: SSH, SOAP, BEEP, TLS - но мы их опустим - SSH стал де-факто стандартом.
Каждый NETCONF запрос содержит элемент (или сообщение):
<rpc>
- это собственно запрос на вызов процедуры с необходимыми параметрами.<rpc-reply>
- ответ на RPC.<rpc-error>
- очевидно, ответная ошибка, когда RPC некорректен.<ok>
- rpc корректен и отработал.
<notification>
- сообщение о событии, инициированное сетевой коробкой - аналог трапа в snmp. (из RFC6241)
Это всё сообщения, внутри которых определённым образом сформированные XML.
<get>
- retrieve running configuration and device state information<get-config>
- retrieve all or part of a specified configuration datastore<edit-config>
- edit a configuration datastore by creating, deleting, merging or replacing content<copy-config>
- copy an entire configuration datastore to another configuration datastore<delete-config>
- delete a configuration datastore<lock>
- lock an entire configuration datastore of a device<unlock>
- release a configuration datastore lock previously obtained with the <lock> operation<close-session>
- request graceful termination of a netconf session<kill-session>
- force the termination of a netconf session
Каждый вендор может расширять список операций хоть до бесконечности. Так, у кого-то, например, есть <copy-config>
.
Установка сессии и Capabilities¶
Так, сначала включаем SSH NETCONF. На примере джунипер.
set system services netconfЭто значит, что SSH будет использоваться как транспорт для указанной подсистемы.Для netconf IANA установила специальный порт 830, хотя часто используется и обычный для SSH 22.
ssh kazan-spine-0.juniper -s netconf <!-- No zombies were killed during the creation of this user interface --> <!-- user eucariot, class j-super-user --> <hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> <capabilities> <capability>urn:ietf:params:netconf:base:1.0</capability> <capability>urn:ietf:params:netconf:capability:candidate:1.0</capability> <capability>urn:ietf:params:netconf:capability:confirmed-commit:1.0</capability> <capability>urn:ietf:params:netconf:capability:validate:1.0</capability> <capability>urn:ietf:params:netconf:capability:url:1.0?scheme=http,ftp,file</capability> <capability>urn:ietf:params:xml:ns:netconf:base:1.0</capability> <capability>urn:ietf:params:xml:ns:netconf:capability:candidate:1.0</capability> <capability>urn:ietf:params:xml:ns:netconf:capability:confirmed-commit:1.0</capability> <capability>urn:ietf:params:xml:ns:netconf:capability:validate:1.0</capability> <capability>urn:ietf:params:xml:ns:netconf:capability:url:1.0?protocol=http,ftp,file</capability> <capability>http://xml.juniper.net/netconf/junos/1.0</capability> <capability>http://xml.juniper.net/dmi/system/1.0</capability> </capabilities> <session-id>15420</session-id> </hello> ]]>]]>
При этом базовые могут расширяться другими стандартизированными capability и даже проприетарными. Давайте рассмотрим сначала стандартные, а потом самые интересные расширенные. Ну и будем называть их «способностями», а то капабилитя - это почти как капибара.
NETCONF Standard Capabilities (стандартные способности)¶
- Candidate configuration
- Эта способность говорит о том. Что коробка поддерживает отдельный кандидат-конфиг, содержащий полную конфигурацию, с которой можно работать без влияния на фактически применённую конфигурацию. Аналоги candidate-config на Juniper.
- Confirmed commit
- Опять же аналог джуниперовоского commit confirmed - откат изменений после коммита, если не было подтверждения коммита.
- Validate
- Способность проверить желаемую конфигурацию до её применения.
- Rollback-on-error
- Способность отмены изменений при ошибке. Работает, если поддерживается способность candidate configuration.
- Writable-running
- Такая способность говорит о том, что устройство позволяет писать непосредственно в running-конфигурацию, в обхода candidate.
- Distinct startup
- Способность задавать startup конфигурацию отличную от running и candidate.
- Notification
- Аналог SNMP-trap. Коробка может слать аварии и события клиенту.
NETCONF Extended Capabilities (сверх-способности)¶
Их тьма. Из самых интересных:
- YANG push
- Способность отсылать данные с коробки на клиент - периодически или по событию.
- YANG-library
- Способность сервера сообщить клиенту о поддерживаемых параметрах относительно YANG: версия, модель, нейспейсы итд.
- Commit-description
- Самоговорящее название.
urn:ietf:params:netconf:capability:{name}:1.0
.urn:ietf:params:netconf:base:1.1
- это имя базовой капабилити для версии 1.1.В ответ на <hello>
сервера клиент в свою очередь должен послать свои capability:
<hello> <capabilities> <capability>urn:ietf:params:xml:ns:netconf:base:1.0</capability> <capability>urn:ietf:params:xml:ns:netconf:capability:candidate:1.0</capability> <capability>urn:ietf:params:xml:ns:netconf:capability:confirmed-commit:1.0</capability> <capability>urn:ietf:params:xml:ns:netconf:capability:validate:1.0</capability> <capability>urn:ietf:params:xml:ns:netconf:capability:url:1.0?protocol=http,ftp,file</capability> <capability>xml.juniper.net/netconf/junos/1.0</capability> <capability>xml.juniper.net/dmi/system/1.0</capability> </capabilities> </hello> ]]>]]>
Чего почти нигде не пишут, но что очень важно: если вы пробуете взаимодействовать с коробкой по нетконф руками, то нужно обязательно вручную отослать такую последовательность ]]>]]>
, сообщающую, что ввод закончен. Она называется Framing Marker или Message Separator Sequence.
Есть важный нюанс, описанный в RFC6242,]]>]]>
- это старый End-of-Message Framing Marker, который был выбран из соображений, что такая последовательность не должна встречаться в well-formed XML. Однако жизнь показала, что она встречается. Поэтому в NETCONF 1.1 придумали новый механизм, который делит данные на блоки - чанки - и нумерует их. Так он и называется: Chunked Framing Mechanism.Каждый чанк данных начинается с##X
, гдеX
- это число октетов в нём.Это одно из фундаментальных отличий между 1.0 и 1.1 :). Другие менее значительны.
Сейчас NETCONF-сессия установлена и можно заслать какой-то RPC.
Посылаем свой первый RPC
<rpc message-id="100" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> <get-config> <source> <running/> </source> <filter type="subtree"> <configuration> <system> <host-name/> </system> </configuration> </filter> </get-config> </rpc> ]]>]]><rpc-reply xmlns:junos="http://xml.juniper.net/junos/14.1R1/junos" message-id="100" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> <data> <configuration xmlns="http://xml.juniper.net/xnm/1.1/xnm" junos:commit-seconds="1644510087" junos:commit-localtime="2022-02-10 16:21:27 UTC" junos:commit-user="eucariot"> <system> <host-name>kzn-spine-0</host-name> </system> </configuration> </data> </rpc-reply>
Мы отправили элемент <rpc>
, в котором запросили <running>
-конфигурацию с помощью операцию <get-config>
. И ещё на сервере отфильтровали по интересной ветке.
А в ответ пришёл <rpc-reply>
с ответом. И в запросе, и в ответе можете найти message-id
- по ним можно отслеживать на что именно ответ - ведь режим работы NETCONF асинхронный и можно засылать следующее сообщение, пока предыдущее ещё не было обработано.
Так за что же так с нами?