Введение в программируемость на основе моделей. Часть вторая NETCONF

Emil Garipov
8 min readJul 14, 2020

--

Продолжим разбирать презентацию Хэнка Престона и Брайна Берна BRKPRG-1368 с Cisco Live US 2019. В этой части рассмотрим NETCONF.

Статьи

  1. Часть первая YANG
  2. Часть вторая NETCONF
  3. Часть треться RESTCONF

Оглавление статьи — NETCONF:

  1. История развития NETCONF
  2. Стэк протокола NETCONF
  3. Сообщения Remote Procedure Call(RPC)
  4. Действия NETCONF
  5. Хранилища данных NETCONF
  6. NETCONF и Python: ncclient
  7. Понимание Перечня возможностей
  8. Автоматизирование своей сети с помощью NETCONF
  9. Резюме NETCONF

История развития NETCONF

Изначально NETCONF вышел в свет в 2006 году и был описан в RFC 4741, а затем был обновлен в 2011 году в RFC 6241. Как заявлено в этом RFC, протокол NETCONF определяет простой механизм, с помощью которого можно управлять сетевым устройством, получать информацию о конфигурации и загружать новые данные конфигурации и манипулировать ими. NETCONF это транспортный протокол, который определяет все данные транспорта — заголовки, пространство IP, аутентификацию, инкапсуляцию, сегментацию и т.д.

Из презентации Хэнка Престона и Брайна Берна

Протокол NETCONF базируется на коммуникации клиент-сервер. Он состоит из управляющего элемента(клиент) и агента(сервер). Управляющим элементом может быть ноутбук, компьютер и т.д., агентами -сетевые устройства.

Из презентации Хэнка Престона и Брайна Берна

Стэк протокола NETCONF

Стэк протокола состоит из 4-х ключевых компонентов.

Из презентации Хэнка Престона и Брайна Берна

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

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

К ним относятся :

  • Формат сообщений — RPC(Remote Procedure Call), которое используется для отправки запроса (<rpc>)и получения отклика(<rpc-reply>). Они ассоциируются с message-id для управления сессией.
  • Действия(Operations), которые предпринимаются после обмена сообщениями RPC. К примеру, можно извлекать или модифицировать различную информацию.
  • Контент, это уже непосредственно сами данные конфигурации и эксплуатации.

Подключение по SSH

Сообщения Remote Procedure Call(RPC)

Протокол NETCONF использует модель связи на основе RPC. Устройства NETCONF используют элементы <rpc> и <rpc-reply> для обеспечения структурирования запросов и ответов NETCONF.

Управляющий элемент отправляет сообщение <rpc> с message-id, ассоциированное с ним. Агент в свою очередь отправляет <rpc-reply>- отклик с massage-id, ассоциированное с управляющим элементом, который совпадает с атрибутом “message-id” <rpc>. Сервер NETCONF также ДОЛЖЕН возвращать любые дополнительные атрибуты включенные в элемент <rpc>, в элементе <rpc-reply> в не измененном виде.

Ниже приведен пример <rpc> и <rpc-reply>. Элемент <rpc> вызывает метод NETCONF <get> и содержит дополнительный атрибут под названием “user-id”. Возвращаемый элемент <rpc-reply> возвращает атрибут “user-id” неизменным , а также возвращает запрашиваемый контент.

<rpc message-id="101"
xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"
xmlns:ex="http://example.net/content/1.0"
ex:user-id="fred">
<get/>
</rpc>
<rpc-reply message-id="101"
xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"
xmlns:ex="http://example.net/content/1.0"
ex:user-id="fred">
<data>
<!-- contents here... -->
</ipv4>
</data>
</rpc-reply>

Это обеспечивает реализацию двух важных функций. Первое: NETCONF-отклик может быть пакетом, состоящим из нескольких пакетов, что может представлять собой отклик с большими данными. При отправке пакета обратно через сеть, massage-id позволяет заново собрать вместе поток данных. И второе, это правильное понимание сессий при одновременной совместной работе(выполнении разных действий разными инженерами) над одним и тем же сетевым устройством.

RPC

Действия NETCONF

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

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

Базовый протокол включает в себя следующие действия:

  • <get> — Извлечение текущей конфигурации и информации о состоянии устройства;
  • <get-config> — Получение всей или части указанной конфигурации базы данных;
  • <edit-config> — Загружает всю или часть указанной конфигурации в указанную целевую базу данных конфигурации;
  • <copy-config> — Заменяет целую базу данных конфигурации на другую;
  • <delete-config> — Удаляет базу данных конфигурации, при этом running-config не может быть удален;
  • <commit> — Копирует альтернативную базу данных в текущую базу данных;
  • <lock> / <unlock> — Блокирует или разблокирует всю систему хранения конфигурационных данных;
  • <close-session> — Запрашивает плавное завершение сессии NETCONF;
  • <kill-session> — Принудительное прекращение сессии NETCONF.

Действия NETCONF

Хранилища данных NETCONF

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

Хранилище данных NETCONF

Коммуникации NETCONF

Коммуникация NETCONF происходит следующим образом.

Сначала отправляется hello сообщение для установки сессии. Следом происходит обмен перечнем возможностей, происходит изучение имеющихся моделей, определяются какие из них следует использовать. Затем составляется действие, которое будет выполнено, к примеру отправляется <get-config> для получения всей или части указанной конфигурации базы данных. Потом отправляется RPC сообщение и после получения RPC-отклика идет соответствующая обработка данных.

Коммуникации NETCONF

NETCONF и Python: ncclient

ncclient — это библиотека Python для клиентов NETCONF. Его цель — предложить интуитивно понятный API, который наглядно отображает XML-кодированную природу конструкций и идиом NETCONF для Python, а также облегчает написание сценариев сетевого управления. Подробнее можно почитать в документации.

ncclient

При использовании ncclient первым делом отправляется hello-сообщение для установки сессии и извлечения перечня возможностей.

Сессия NETCONF с устройством открывается через manager.connect(), при помощи которого на устройство поставляются параметры сессии: имя хоста, порта, имя пользователя, пароль. Всякий раз, когда нужно создать сессию для выполнения действия в скрипте, вызывается переменная m( “as m”). Для извлечения возможностей сессии используется m.server_capabilities().

Скрипты примеров можно скачать отсюда и отсюда.

Hello сообщение

Понимание Перечня возможностей

Аннонсирование возможностей осуществляется в сообщениях, рассылаемых каждым из участников во время установления сессии. Когда сессия NETCONF открыта, каждый равноправный участник (как клиент, так и сервер) должен отправить сообщение <hello>, содержащее список возможностей этого равноправного участника. Каждый участник ДОЛЖЕН отправлять как минимум базовую возможность NETCONF.

"urn:ietf:params:netconf:base:1.1"

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

Среди них выделяется два типа:

  • Базовые возможности NETCONF,выделенные голубым цветов в презентации.
  • Поддерживаемые модели данных, выделенные зеленым цветом в презентации. Это все модели YANG, поддерживаемые устройством, с которым идет взаимодействие.

Если взглянуть далее, то первой строкой идет наименование модели YANG, в данном случае:

ietf(urn:ietf:params:xml:ns:yang:ietf-interfaces)

Следом наименование модуля:

? module=ietf-interfaces

Номер ревизии, в примере показан в виде даты. Разные устройства могут использовать различные номера ревизий:

& revision=2014-05-08

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

& features=pre-provisioning,if-mib,arbitrary-names

Следующая строка это указание на исключения в модели. Об исключениях можно прочитать в первой части статьи:

& deviations=ietf-ip-devs

И последнее это строки исключений из модуля Cisco, в которой перечислены исключения:

http://cisco.com/ns/ietf-ip/devs
? module=ietf-ip-devs
& revision=2016-08-10

Автоматизирование своей сети с помощью NETCONF

Получение сведений об интерфейсе с помощью XML-фильтра

Для демонстрации используется скрипт example2.py из презентации. При извлечении информации используется ncclient. Отправляем запрос <get>, который позволяет получить текущую конфигурацию и информацию о состоянии устройства. С помощью <get> вся информация возвращается в приложение питона, где ее можно разобрать, чтобы получить нужную информацию. При этом <get> может вернуть целую конфигурацию XML, что может негативно сказаться на полосе пропускания. Для того, чтобы этого не случилось нам необходимо вычленить только необходимую информацию, использовав XML-фильтр. В примере используется готовый шаблон XML-фильтра для получения информации по интерфейсам:

open("filter-ietf-interfaces.xml").read()

Ниже видно, что в данном случае мы запрашиваем информацию в виде XML-фильтра об интерфейсе GigabitEthernet2 из контейнера ietf-интерфейсов модуля YANG. В строке <interfaces-state> запрашиваются эксплуатационные детали интерфейса:

</filter>
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
<interface>
<name>GigabitEthernet2</name>
</interface>
</interfaces>
<interfaces-state xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
<interface>
<name>GigabitEthernet2</name>
</interface>
</interfaces-state>

Далее с помощью функции m.get(netconf_filter) XML-фильтр отправляется на устройство. Для парсинга поступившей информации используется модуль xmltodict, который позволяет перевести данные из формата XML в формат словаря Python для дальнейшей обработки.

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

Получение сведений об интерфейсе с помощью XPath:

XPath фильтр может быть использован для выбора определенных критериев, которые должны быть возвращены в ответ на запрос. XPath фильтр возвращает специфические критерии, т.е. может выбирать элементы из модели, которые соответствуют критериям, выраженным в фильтре. В отличие от XML-фильтра, указывается тип XPath, а затем предоставляется точный путь рамках структуры данных XML, к выводу, который необходимо получить. К примеру, если необходимо отслеживать количество исходящих unicast пакетов на интерфейсе можно настроить XPath таким образом, чтобы можно было зациклить запрос к маршрутизатору на каждые 5 секунд и получать сообщения.

После выполнения скрипта вывод будет следующим:

Конфигурирование деталей интерфейса

При конфигурировании интерфейса используется шаблон в формате XML и скрипт на Python. Шаблон XML в точности повторяет модель данных YANG, описанную в первой части статьи. Данный шаблон в скрипте открывается стандартной командой питона:

open("config-temp-ietf-interfaces.xml").read()

Шаблон начинается со строки <config>, за ней следует контейнер “urn:ietf:params:xml:ns:yang:ietf-interfaces”, затем список интерфейсов и наименование интерфейса, который будет конфигурироваться “<name>{int_name}</name>”. Ну и соответственно параметры, которые будут прописаны на интерфейсе: описание, ip адрес, маска подсети.

<config>
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
<interface>
<name>{int_name}</name>
<description>{int_desc}</description>
<type xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type">ianaift:ethernetCsmacd</type>
<enabled>true</enabled>
<ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
<address>
<ip>{ip_address}</ip>
<netmask>{subnet_mask}</netmask>
</address>
</ipv4>
</interface>
</interfaces>
</config>

Следующим шагом назначаем переменной “netconf_payload” необходимые параметры, которые мы хотим применить на интерфейсе:

Далее выполняется действие <edit-config> по отправке конфигурации, прописанной в “netconf_payload”, в running-config на устройстве через сессию “netconf_reply”:

netconf_reply = m.edit_config(netconf_payload, target="running")

Если все прошло удачно, то вернется rpc — отклик от устройства с ключом <ok>:

Сохранение Running Configuration при помощи ncclient

Running configuration можно сохранить в startup configuration отправив сообщение NETCONF RPC в формате YANG на устройство. В данном примере используется следующий скрипт на Python . Создается полезная нагрузка XML для RPC, с использованием “cisco-ia” модуля в виде значения переменной “save_body”. Для отправки XML строки на устройство используется метод dispatch.

m.dispatch(xml_.to_ele(save_body))

После удачного выполнения кода на устройстве, он пришлет следующий<rpc-reply> — отклик с успешным выполнением команды(подчеркнуто красным):

Резюме NETCONF

  • NETCONF — протокол, ориентированный на соединение. Используются SSH, TLS как транспорт;
  • Клиент NETCONF (“manager”) устанавливает сессию с сервером (“agent”);
  • Данные кодируются в виде XML;
  • Базируется на RPC;
  • Определен в RFC4741 (NETCONF 1.0) и RFC6241 (NETCONF 1.1);
  • Возможность инициировать соединение со стороны устройства.

Присоединяйтесь к каналу Devnet

--

--