RFC 8423 Reclassification of Suite B Documents to Historic Status

Internet Engineering Task Force (IETF)                        R. Housley
Request for Comments: 8423                                Vigil Security
Category: Informational                                       L. Zieglar
ISSN: 2070-1721                                 National Security Agency
                                                               July 2018

Перевод документов Suite B в статус Historic

Reclassification of Suite B Documents to Historic Status

PDF

Аннотация

Этот документ переводит RFC, относящиеся к набору криптографических алгоритмов Suite B Агентства национальной безопасности США (NSA1), в статус устаревших (Historic) и рассматривает причины этого. Документ переводит в число устаревших информационные RFC 5759, 6239, 6318, 6379, 6380, 6403 и 6460. Кроме того, в статус Historic переводятся три отмененных (obsoleted) информационных RFC 4869, 5008 и 5430.

Статус документа

Документ не содержит спецификации Internet Standards Track и публикуется с информационными целями.

Документ является результатом работы IETF2 и представляет согласованный взгляд сообщества IETF. Документ прошел открытое обсуждение и был одобрен для публикации IESG3. Не все документы, одобренные IESG, претендуют на статус стандартов Internet, как указано в разделе 2 в RFC 7841.

Информацию о текущем статусе документа, ошибках и способах обратной связи можно найти по ссылке https://www.rfc-editor.org/info/rfc8423.

Авторские права

Авторские права (Copyright (c) 2018) принадлежат IETF Trust и лицам, указанным в качестве авторов документа. Все права защищены.

К документу применимы права и ограничения, указанные в BCP 78 и IETF Trust Legal Provisions и относящиеся к документам IETF (http://trustee.ietf.org/license-info), на момент публикации данного документа. Прочтите упомянутые документы внимательно. Фрагменты программного кода, включённые в этот документ, распространяются в соответствии с упрощённой лицензией BSD, как указано в параграфе 4.e документа IETF Trust Legal Provisions, без каких-либо гарантий (как указано в Simplified BSD License).

1. Введение

Несколько RFC задавали профили протоколов защиты для использования с криптографией АНБ Suite B. Алгоритмы Suite B больше не поддерживаются АНБ и web-страницы со спецификациями этих криптографических алгоритмов больше не доступны.

А июле 2015 года АНБ опубликовало Committee for National Security Systems Advisory Memorandum 02-15 в качестве первого шага по замене алгоритмов Suite B алгоритмами набора CNSA4. Информацию об этих алгоритмах можно найти в [CNSA].

2. Обоснование

Как указано в [CNSA], АНБ переходит с алгоритмов Suite B к алгоритмам CNSA. В результате профили протоколов защиты для алгоритмов Suite B в дальнейшем представляют лишь исторический интерес.

3. RFC, относящиеся к Suite B

В интервале с 2007 г. по 2012 г. было опубликовано несколько относящихся к Suite B документов RFC с профилями протоколов защиты, использующих алгоритмы Suite B. Эти документы перечислены ниже.

  • [RFC4869], «Suite B Cryptographic Suites for IPsec» (отменен RFC 6379).

  • [RFC5008], «Suite B in Secure/Multipurpose Internet Mail Extensions (S/MIME)» (отменен RFC 6318).

  • [RFC5430], «Suite B Profile for Transport Layer Security (TLS)» (отменен RFC 6460).

  • [RFC5759], «Suite B Certificate and Certificate Revocation List (CRL) Profile».

  • [RFC6239], «Suite B Cryptographic Suites for Secure Shell (SSH)».

  • [RFC6318], «Suite B in Secure/Multipurpose Internet Mail Extensions (S/MIME)».

  • [RFC6379], «Suite B Cryptographic Suites for IPsec».

  • [RFC6380], «Suite B Profile for Internet Protocol Security (IPsec)».

  • [RFC6403], «Suite B Profile of Certificate Management over CMS».

  • [RFC6460], «Suite B Profile for Transport Layer Security (TLS)».

4. Документы, ссылающиеся на связанные с Suite B RFC

Эти RFC неоднократно ссылаются один на другой. Такие перекрестные ссылки далее в этом документе не рассматриваются.

В других RFC также имеются ссылки на связанные с Suite B RFC, эти ссылки рассматриваются в следующих параграфах.

4.1. Документы со ссылками на RFC 4869

В одном RFC имеется ссылка на RFC 4869 [RFC4869].

RFC 6071, «IP Security (IPsec) and Internet Key Exchange (IKE) Document Roadmap» [RFC6071] указывает, что RFC 4869 добавляет 4 предопределенных шифра на основе спецификаций Suite B:

  • шифр IKE/ESP «Suite-B-GCM-128»;

  • шифр IKE/ESP «Suite-B-GCM-256»;

  • шифр IKE/ESP «Suite-B-GMAC-128»;

  • шифр IKE/ESP «Suite-B-GMAC-256».

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

4.2. Документы со ссылками на RFC 5759

В одном RFC имеется ссылка на RFC 5759 [RFC5759].

RFC 6187, «X.509v3 Certificates for Secure Shell Authentication» [RFC6187] указывает, что RFC 5759 содержит дополнительные рекомендации для использования ключей ECDSA5 с Suite B.

4.3. Документы со ссылками на RFC 6379

В одном RFC имеется ссылка на RFC 6379 [RFC6379].

RFC 7321, «Cryptographic Algorithm Implementation Requirements and Usage Guidance for Encapsulating Security Payload (ESP) and Authentication Header (AH)» [RFC7321] указывает, что алгоритм AES-GCM используется в Suite B и этот алгоритм стал предпочтительным методом аутентифицированного шифрования в IPsec. RFC 7321 был отменен RFC 8221.

4.4. Документы со ссылками на RFC 6403

В двух RFC имеются ссылки на RFC 6403 [RFC6403].

RFC 6402, «Certificate Management over CMS (CMC) Updates» [RFC6402] указывает, что разработка профиля для Suite B показала необходимость внесенных этим документом обновлений.

RFC 7030, «Enrollment over Secure Transport» [RFC7030] указывает, что сценарии из Приложения к RFC 6403 очень похожи на три описанных сценария.

4.5. Документы со ссылками на RFC 6460

В двух RFC имеются ссылки на RFC 6460 [RFC6460].

RFC 6605, «Elliptic Curve Digital Signature Algorithm (DSA) for DNSSEC» [RFC6605] заявляет о копировании части материала из RFC 6460. Статус Standards Track для RFC 6605 не меняется в результате перевода RFC 6460 в состояние Historic.

RFC 7525, «Recommendations for Secure Use of Transport Layer Security (TLS) and Datagram Transport Layer Security (DTLS)» [RFC7525] отмечает, что профиль Suite B для TLS 1.2 использует разные шифронаборы.

RFC 8253, «PCEPS: Usage of TLS to Provide a Secure Transport for the Path Computation Element Communication Protocol (PCEP)» [RFC8253] указывает на RFC 6460 для шифронаборов TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 и TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384. Оба эти шифронабора определены в [RFC5289], на который было бы лучше сослаться. Статус Standards Track для RFC 8253 не меняется в результате перевода RFC 6460 в состояние Historic.

5. Влияние перевода связанных с Suite B RFC в статус Historic

Не возникает каких-либо проблем взаимодействия или безопасности в результате перевода связанных с Suite B RFC в статус Historic. Как указано в разделе 4, ни один из переведенных в число устаревших RFC не содержит явной спецификации криптографического алгоритма или идентификатора криптоалгоритма.

6. Взаимодействие с IANA

Документ не требует действий со стороны IANA.

7. Вопросы безопасности

Не возникает каких-либо проблем взаимодействия или безопасности в результате перевода связанных с Suite B RFC в статус Historic.

АНБ отказывается от некоторых криптографических алгоритмов и размеров ключей, которые были использованы в профилях Suite B.

8. Литература

8.1. Нормативные документы

[RFC4869] Law, L. and J. Solinas, «Suite B Cryptographic Suites for IPsec», RFC 4869, DOI 10.17487/RFC4869, May 2007, <https://www.rfc-editor.org/info/rfc4869>.

[RFC5008] Housley, R. and J. Solinas, «Suite B in Secure/Multipurpose Internet Mail Extensions (S/MIME)», RFC 5008, DOI 10.17487/RFC5008, September 2007, <https://www.rfc-editor.org/info/rfc5008>.

[RFC5430] Salter, M., Rescorla, E., and R. Housley, «Suite B Profile for Transport Layer Security (TLS)», RFC 5430, DOI 10.17487/RFC5430, March 2009, <https://www.rfc-editor.org/info/rfc5430>.

[RFC5759] Solinas, J. and L. Zieglar, «Suite B Certificate and Certificate Revocation List (CRL) Profile», RFC 5759, DOI 10.17487/RFC5759, January 2010, <https://www.rfc-editor.org/info/rfc5759>.

[RFC6239] Igoe, K., «Suite B Cryptographic Suites for Secure Shell (SSH)», RFC 6239, DOI 10.17487/RFC6239, May 2011, <https://www.rfc-editor.org/info/rfc6239>.

[RFC6318] Housley, R. and J. Solinas, «Suite B in Secure/Multipurpose Internet Mail Extensions (S/MIME)», RFC 6318, DOI 10.17487/RFC6318, June 2011, <https://www.rfc-editor.org/info/rfc6318>.

[RFC6379] Law, L. and J. Solinas, «Suite B Cryptographic Suites for IPsec», RFC 6379, DOI 10.17487/RFC6379, October 2011, <https://www.rfc-editor.org/info/rfc6379>.

[RFC6380] Burgin, K. and M. Peck, «Suite B Profile for Internet Protocol Security (IPsec)», RFC 6380, DOI 10.17487/RFC6380, October 2011, <https://www.rfc-editor.org/info/rfc6380>.

[RFC6403] Zieglar, L., Turner, S., and M. Peck, «Suite B Profile of Certificate Management over CMS», RFC 6403, DOI 10.17487/RFC6403, November 2011, <https://www.rfc-editor.org/info/rfc6403>.

[RFC6460] Salter, M. and R. Housley, «Suite B Profile for Transport Layer Security (TLS)», RFC 6460, DOI 10.17487/RFC6460, January 2012, <https://www.rfc-editor.org/info/rfc6460>.

8.2. Дополнительная литература

[CNSA] National Security Agency, «Commercial National Security Algorithm Suite», August 2015, <https://www.iad.gov/iad/programs/iad-initiatives/cnsa-suite.cfm>.

[RFC5289] Rescorla, E., «TLS Elliptic Curve Cipher Suites with SHA-256/384 and AES Galois Counter Mode (GCM)», RFC 5289, DOI 10.17487/RFC5289, August 2008, <https://www.rfc-editor.org/info/rfc5289>.

[RFC6071] Frankel, S. and S. Krishnan, «IP Security (IPsec) and Internet Key Exchange (IKE) Document Roadmap», RFC 6071, DOI 10.17487/RFC6071, February 2011, <https://www.rfc-editor.org/info/rfc6071>.

[RFC6187] Igoe, K. and D. Stebila, «X.509v3 Certificates for Secure Shell Authentication», RFC 6187, DOI 10.17487/RFC6187, March 2011, <https://www.rfc-editor.org/info/rfc6187>.

[RFC6402] Schaad, J., «Certificate Management over CMS (CMC) Updates», RFC 6402, DOI 10.17487/RFC6402, November 2011, <https://www.rfc-editor.org/info/rfc6402>.

[RFC6605] Hoffman, P. and W. Wijngaards, «Elliptic Curve Digital Signature Algorithm (DSA) for DNSSEC», RFC 6605, DOI 10.17487/RFC6605, April 2012, <https://www.rfc-editor.org/info/rfc6605>.

[RFC7030] Pritikin, M., Ed., Yee, P., Ed., and D. Harkins, Ed., «Enrollment over Secure Transport», RFC 7030, DOI 10.17487/RFC7030, October 2013, <https://www.rfc-editor.org/info/rfc7030>.

[RFC7321] McGrew, D. and P. Hoffman, «Cryptographic Algorithm Implementation Requirements and Usage Guidance for Encapsulating Security Payload (ESP) and Authentication Header (AH)», RFC 7321, DOI 10.17487/RFC7321, August 2014, <https://www.rfc-editor.org/info/rfc7321>.

[RFC7525] Sheffer, Y., Holz, R., and P. Saint-Andre, «Recommendations for Secure Use of Transport Layer Security (TLS) and Datagram Transport Layer Security (DTLS)», BCP 195, RFC 7525, DOI 10.17487/RFC7525, May 2015, <https://www.rfc-editor.org/info/rfc7525>.

[RFC8253] Lopez, D., Gonzalez de Dios, O., Wu, Q., and D. Dhody, «PCEPS: Usage of TLS to Provide a Secure Transport for the Path Computation Element Communication Protocol (PCEP)», RFC 8253, DOI 10.17487/RFC8253, October 2017, <https://www.rfc-editor.org/info/rfc8253>.

Адреса авторов

Russ Housley

Vigil Security, LLC

918 Spring Knoll Drive

Herndon, VA 20170

United States of America

Email: housley@vigilsec.com

Lydia Zieglar

National Security Agency

9800 Savage Road

Ft. George G. Meade, MD 20755-6940

United States of America

Email: llziegl@nsa.gov


Перевод на русский язык

Николай Малых

nmalykh@gmail.com

1United States National Security Agency.

2Internet Engineering Task Force.

3Internet Engineering Steering Group.

4Commercial National Security Algorithm — коммерческий алгоритм национальной безопасности.

5Elliptic Curve Digital Signature Algorithm — алгоритм цифровой подписи на основе эллиптической кривой.

Рубрика: RFC | Комментарии к записи RFC 8423 Reclassification of Suite B Documents to Historic Status отключены

RFC 8402 Segment Routing Architecture

Internet Engineering Task Force (IETF)                  C. Filsfils, Ed.
Request for Comments: 8402                               S. Previdi, Ed.
Category: Standards Track                                    L. Ginsberg
ISSN: 2070-1721                                      Cisco Systems, Inc.
                                                             B. Decraene
                                                            S. Litkowski
                                                                  Orange
                                                               R. Shakir
                                                            Google, Inc.
                                                               July 2018

Архитектура маршрутизации по сегментам

Segment Routing Architecture

PDF

Аннотация

Маршрутизация по сегментам (SR1) использует парадигму маршрутизации, заданной отправителем (source routing). Узел направляет пакет с помощью упорядоченного списка инструкций, называемых сегментами. Сегмент может представлять инструкцию, основаннe. на топологии или услугах. Семантика сегмента может быть локальной для узла SR или глобальной в рамках домена SR. Маршрутизация по сегментам обеспечивает механизм, который позволяет ограничивать потоки конкретным топологическим путем при поддержке состояний на уровне потока лишь на входных узлах домена SR.

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

SR можно использовать с архитектурой IPv6 с новым типом заголовка маршрутизации. Сегмент представляется в виде адреса IPv6, а упорядоченный список сегментов — в виде упорядоченного списка адресов IPv6 в заголовке маршрутизации. Активный сегмент указывается адресом получателя (DA2) пакета. Следующий активный сегмент задается указателем в новом заголовке маршрутизации.

Статус документа

Документ относится к категории Internet Standards Track.

Документ является результатом работы IETF3 и представляет согласованный взгляд сообщества IETF. Документ прошел открытое обсуждение и был одобрен для публикации IESG4. Дополнительную информацию о стандартах Internet можно найти в разделе 2 в RFC 7841.

Информацию о текущем статусе документа, ошибках и способах обратной связи можно найти по ссылке https://www.rfc-editor.org/info/rfc8402.

Авторские права

Авторские права (Copyright (c) 2018) принадлежат IETF Trust и лицам, указанным в качестве авторов документа. Все права защищены.

К документу применимы права и ограничения, указанные в BCP 78 и IETF Trust Legal Provisions и относящиеся к документам IETF (http://trustee.ietf.org/license-info), на момент публикации данного документа. Прочтите упомянутые документы внимательно. Фрагменты программного кода, включённые в этот документ, распространяются в соответствии с упрощённой лицензией BSD, как указано в параграфе 4.e документа IETF Trust Legal Provisions, без каких-либо гарантий (как указано в Simplified BSD License).

1. Введение

Маршрутизация по сегментам (SR) использует парадигму маршрутизации, заданной отправителем (source routing). Узел направляет пакет с помощью упорядоченного списка инструкций, называемых сегментами. Сегмент может представлять инструкцию, основанная на топологии или услугах. Семантика сегмента может быть локальной для узла SR или глобальной в рамках домена SR. Маршрутизация по сегментам обеспечивает механизм, который позволяет ограничивать потоки конкретным топологическим путем при поддержке состояний на уровне потока лишь на входных узлах домена SR.

Сегменты часто указывают их идентификаторами SID5.

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

Сегмент может быть связан с сервисной инструкцией (например, пакет следует обрабатывать в контейнере или виртуальной машине (VM6), связанной с сегментом). Сегмент может быть связан с трактовкой QoS (например, предоставление для пакетов данного сегмента пропускной способности x Мбит/с).

Архитектура SR поддерживает любые типы связанных с сегментами инструкций.

Архитектура SR поддерживает любой тип уровня управления — распределенный, централизованный или гибридный.

В распределенном варианте выделение сегментов и сигнализация обеспечиваются протоколом IS-IS, OSPF или BGP. Узел сам решает вопрос направления пакетов в SR Policy (например, заранее рассчитанная локальная защита [RFC8355]). Узел индивидуально рассчитывает SR Policy.

В централизованном варианте сегменты выделяются и создаются контроллером SR. Контроллер SR решает, какие узлы должны направлять пакеты в соответствии с правилами заданной отправителем маршрутизации. Контроллер SR рассчитывает правила заданной отправителем маршрутизации. Архитектура SR не ограничивает способы программирования сети контроллером. Возможными вариантами такого программирования являются протоколы NETCONF7, PCEP8 и BGP. Архитектура SR не ограничивает число контроллеров SR. В частности, может применяться множество контроллеров для программирования одного домена SR. Архитектура SR позволяет этим контроллерам обнаруживать экземпляры SID и определять узлы, где они созданы, а также определять доступность на узлах локальных (SRLB) и глобальных (SRGB) меток.

В гибридном варианте базовый распределенный уровень управления дополняется центральным контроллером. Например, при размещении адресата за пределами домена IGP контроллер SR может рассчитать SR Policy от имени узла IGP. Архитектура SR не ограничивает способы взаимодействия узлов, участвующих в управлении, с контроллером SR. Возможными вариантами являются протоколы PCEP и BGP.

Хосты могут быть частью домена SR. Центральный контроллер может информировать хосты о правилах путем их выталкивания на хосты (pushing) или путем ответов на запросы хостов.

Экземпляры архитектуры SR могут создаваться для различных уровней данных. В этом документе рассматриваются два таких экземпляра — SR для MPLS (SR-MPLS) и SR для IPv6 (SRv6).

SR можно применять непосредственно к архитектуре MPLS без изменения уровня пересылки [SR-MPLS]. Сегменты представляются в виде меток MPLS. Экземпляры SR Policy создаются в форме стека меток. Обрабатываемым (активным) сегментом является сегмент на вершине стека. По завершению обработки сегмента соответствующая метка выталкивается из стека.

SR можно применять в архитектуре IPv6 с использованием нового типа заголовков маршрутизации, называемого заголовком SR (SRH9) [IPv6-SRH]. Связанная с сегментом инструкция представляется в виде адреса IPv6. Сегменты SRv6 называют также SRv6 SID. Экземпляр SR Policy создается в форме упорядоченного списка SRv6 SID в заголовке маршрутизации. Активный сегмент указывается адресом получателя (DA) в пакете. Следующий активный сегмент задается указателем SegmentsLeft (SL) в SRH. По завершении обработки SRv6 SID значение SL декрементируется и в DA копируется следующий сегмент. Когда пакет направляется SR Policy, в него добавляется соответствующий заголовок SRH.

В контексте распределенного уровня управления на базе IGP определяется два топологических сегмента — IGP-Adjacency и IGP-Prefix.

В контексте распределенного уровня управления на базе BGP определяется два топологических сегмента — BGP peering и BGP-Prefix.

Головная точка (headend) SR Policy связывает SID (сегмент Binding или BSID) со своей политикой. Когда головная точка получает пакет, активный сегмент которого соответствуют BSID локальной политики SR, она направляет пакет в SR Policy.

Этот документ определяет сегменты IGP, BGP и Binding для уровней данных SR-MPLS и SRv6.

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

2. Терминология

Ключевые слова необходимо (MUST), недопустимо (MUST NOT), требуется (REQUIRED), нужно (SHALL), не следует (SHALL NOT), следует (SHOULD), не нужно (SHOULD NOT), рекомендуется (RECOMMENDED), не рекомендуется (NOT RECOMMENDED), возможно (MAY), необязательно (OPTIONAL) в данном документе интерпретируются в соответствии с BCP 14 [RFC2119] [RFC8174] тогда и только тогда, когда они выделены шрифтом, как показано здесь.

SR-MPLS

Экземпляр SR для уровня данных MPLS.

SRv6

Экземпляр SR для уровня данных IPv6.

Segment — сегмент

Инструкция, выполняемая узлом для входящего пакета (например, пересылка по кратчайшему пути к адресату, пересылка через конкретный интерфейс или доставка определенному экземпляру приложения или сервиса).

SID

Идентификатор сегмента. Отметим, что термин SID часто используется вместо термина «сегмент», хотя технически это не совсем точно.

SR-MPLS SID

Метка MPLS или значение индекса в пространстве меток MPLS, явно связанные с сегментом.

SRv6 SID

Адрес IPv6, явно связанный с сегментом.

Segment Routing domain (SR domain) – домен SR

Множество узлов, участвующих в модели заданной отправителем маршрутизации. Эти узлы могут быть соединены в одну физическую инфраструктуру (например, сеть сервис-провайдера). Узлы могут также быть связаны удаленными соединениями (например, VPN организации или наложенная сеть). При использовании множества протоколов домен SR обычно будет включать все экземпляры сетевых протоколов. Однако в некоторых случаях может быть желательно разделение сети на множество доменов SR, каждый из которых включает один или несколько экземпляров протоколов. Предполагается, что все узлы в домене SR имеют общее администрирование.

Active Segment – активный сегмент

Сегмент, используемый принимающим маршрутизатором для обработки пакета. Для MPLS это верхняя метка в стеке, для IPv6 — адрес получателя [IPv6-SRH].

PUSH — вталкивание

Операция вставки сегмента на вершину списка сегментов. Для SR-MPLS вершиной списка является верхняя (внешняя) метка в стеке. Для SRv6 вершина списка сегментов представлена первым сегментом в заголовке SRH, как определено в [IPv6-SRH].

NEXT – следующий сегмент

При завершении обработки активного сегмента NEXT является операцией проверки следующего сегмента, который становится активным. В SR-MPLS операция NEXT реализуется выталкиванием (POP) верхней метки, в SRv6 — копированием следующего сегмента из SRH в поле адреса получателя заголовка IPv6.

CONTINUE – продолжение сегмента

Активный сегмент не завершен, поэтому он остается активным. В SR-MPLS операция CONTINUE реализуется заменой (SWAP) верхней метки [RFC3031], в SRv6 это обычная операция пересылки IPv6 в соответствии с адресом получателя IPv6.

SR Global Block (SRGB) – глобальный блок SR

Набор глобальных сегментов в домене SR. Если узел участвует в нескольких доменах SR, для каждого из них будет присутствовать блок SRGB. В SR-MPLS блок SRGB является локальным свойством узла и указывает множество локальных меток, зарезервированных для глобальных сегментов. В SR-MPLS настоятельно рекомендуется использовать одинаковые блоки SRGB на всех узлах домена SR. Это упрощает работу и поиск неисправностей, поскольку на каждом узле одна и та же метка будет представлять один и тот же сегмент. В SRv6 блок SRGB представляет собой набор глобальных SRv6 SID в домене SR.

SR Local Block (SRLB) – локальный болк SR

Локальное свойство узла SR. Если узел участвует в нескольких доменах SR, используется один блок SRLB для каждого домена SR. В SR-MPLS блок SRLB представляет собой набор локальных меток, зарезервированных для локальных сегментов. В SRv6 блок SRLB представляет собой набор локальных адресов IPv6, зарезервированных для локальных SRv6 SID. В управляемой контроллерами сети некоторые контроллеры или приложения могут использовать уровень управления для определения доступного набора локальных сегментов.

Global Segment – глобальный сегмент

Сегмент, являющийся частью SRGB домена. Связанная с сегментом инструкция определяется на уровне домена SR. Типичным примером глобального сегмента является топологический кратчайший путь к данному адресату внутри домена SR.

Local Segment – локальный сегмент

В SR-MPLS это локальная метка вне SRGB. Это может быть часть явно анонсируемого SRLB. В SRv6 это может быть любой адрес IPv6 (т. е. адрес может быть частью SRGB, но используется так, что его значимость локальна). Инструкция, связанная с сегментом, определяется на уровне узла.

IGP Segment – сегмент IGP

Базовое имя для сегмента, присоединенного к части информации, анонсируемой link-state IGP (например, префикс или смежность IGP).

IGP-Prefix Segment – сегмент IGP-Prefix

Сегмент IGP-Prefix является сегментом IGP, представляющим префикс IGP. Когда сегмент IGP-Prefix является глобальным в рамках экземпляра или топологии SR IGP, он определяет инструкцию для пересылки пакета по пути, рассчитанному с использованием алгоритма маршрутизации, заданного в поле algorithm, для топологии и экземпляра IGP, где этот сегмент анонсируется. Используется также термин prefix segment (сегмент префикса).

Prefix-SID

Идентификатор SID для сегмента IGP-Prefix.

IGP-Anycast Segment — сегмент IGP-Anycast

Сегмент IGP-Anycast является сегментом IGP-Prefix, который указывает префикс anycast, анонсируемый набором маршрутизаторов.

Anycast-SID

Идентификатор SID для сегмента IGP-Anycast.

IGP-Adjacency Segment – сегмент IGP-Adjacency

Сегмент IGP-Adjacency является сегментом IGP, присоединенным к однонаправленной смежности или набору таких смежностей. По умолчанию сегмент IGP-Adjacency является локальным (если явно не анонсируется иное) для анонсирующего его узла. Называется также Adj-SID.

Adj-SID

Идентификатор SID для сегмента IGP-Adjacency.

IGP-Node Segment – сегмент IGP-Node

Сегмент IGP-Node является сегментом IGP-Prefix, который указывает конкретный маршрутизатор (например, loopback). Называется также Node Segment 9сегмент узла).

Node-SID

Идентификатор SID для сегмента IGP-Node.

SR Policy – правила (политика) SR

Упорядоченный список сегментов. Головная точка SR Policy направляет пакеты в SR Policy. Список сегментов может быть задан явно в SR-MPLS как стек меток и в SRv6 как упорядоченный список SRv6 SID. Кроме того, список сегментов рассчитывается на основе адресата и набора параметров оптимизации и ограничений (например, задержка, сродство, SRLG и т. п.). Расчет может выполняться локально или передаваться серверу PCE. SR Policy может настраиваться оператором, а также обеспечиваться протоколом NETCONF [RFC6241] или PCEP [RFC5440]. Политика SR может применяться для организации трафика (TE10), решения задач OAM11 или быстрой смены маршрутов (FRR12).

Segment List Depth – размер списка сегментов

Число сегментов в SR Policy. Объект, создающий экземпляр SR Policy на узле N, должен быть способен определить возможности sdepth-insertion для узла N. Например, анонсирование свойства PCEP SR, описанное в [PCEP-SR-EXT], является одним из способов обнаружения возможности.

Forwarding Information Base (FIB) – база данных о пересылке

Таблица пересылки узла.

3. Сегменты Link-State IGP

В домене SR узел IGP с поддержкой SR анонсирует сегменты для своих подключенных префиксов и смежностей (соседств). Эти сегменты называют сегментами IGP или IGP SID. Они играют важную роль в SR и позволяют выразить любой путь через домен SR. Такой путь выражается одним сегментом IGP или списком из множества сегментов IGP.

Для анонсирования сегментов IGP требуется расширение протоколов IGP, основанных на состоянии каналов. Эти расширения определены в [ISIS-SR-EXT], [OSPF-SR-EXT] и [OSPFv3-SR-EXT].

3.1. Сегмент IGP-Prefix (Prefix-SID)

Сегмент IGP-Prefix является сегментом IGP, присоединенным к префиксу IGP. Сегмент IGP-Prefix является глобальным (если явно не указано иное) в домене SR. Контекст сегмента IGP-Prefix включает префикс, топологию и алгоритм. Может быть выделено множество SID для одного префикса, пока триплеты <prefix, topology, algorithm> являются уникальными.

Множество экземпляров и топологий определены для IS-IS и OSPF в [RFC5120], [RFC8202], [RFC6549] и [RFC4915].

3.1.1. Алгоритм Prefix-SID

SR поддерживает использование множества алгоритмов маршрутизации, т. е. может поддерживаться множество разных расчетов кратчайшего пути с учетом ограничений. Идентификатор алгоритма включается в анонс Prefix-SID. Определяющий алгоритм документ должен включать спецификацию расчета пути для этого алгоритма.

Данный документ определяет два алгоритма.

  • По кратчайшему пути (SPF13). Этот алгоритм используется по умолчанию. Пакет пересылается с использованием общепринятого алгоритма SPF, знающего о ECMP14, который реализуется протоколами IGP. Однако промежуточным точкам явно разрешено применять другие алгоритмы пересылки в соответствии с локальной политикой. Алгоритм SPF фактический является используемым по умолчанию в большинстве современных сетей, где локальные правила могут переопределять решение SPF.

  • Строго по кратчайшему пути (Strict-SPF). Этот алгоритм требует пересылать пакет в соответствии с алгоритмом SPF, знающим о ECMP, и инструктирует все маршрутизаторы на пути игнорировать любые локальные правила, переопределяющие решение SPF. Идентификатор SID, анонсируемый с алгоритмом Strict-SPF, обеспечивает неизменность пути SPF, по которому пересылается пакет. Отметим, что механизмы быстройсмены маршрутов (FRR) [RFC5714] совместимы с этим алгоритмом. Иными словами, пакет, полученный с Strict-SPF SID, может быть перемаршрутизирован механизмом FRR. Strict-SPF использует такую же топологию, как алгоритм SPF. Обычно узлы, не поддерживающие Strict-SPF, не будут создавать записей пересылки для этого алгоритма. Ограничение топологии лишь узлами, поддерживающими этот алгоритм, не создает желаемых путей пересылки, поскольку желаемое поведение состоит в следовании маршрутам, рассчитанным по алгоритму SPF. Поэтому исходному узлу SR недопустимо использовать SR Policy с сегментом Strict-SPF, если путь проходит через узлы, не поддерживающие алгоритм Strict-SPF.

Сегмент IGP-Prefix указывает путь к соответствующему префиксу, рассчитанный с использованием привязанного алгоритма. Предполагается, что пакет внесенный где-либо внутри домена SR с активным Prefix-SID, будет пересылаться по пути, рассчитанному с использованием указанного алгоритма. Для этого требуется полносвязная топология маршрутизаторов, поддерживающих этот алгоритм.

3.1.2. SR-MPLS

Когда SR используется с уровнем данных MPLS, идентификаторы SID являются метками MPLS или индексами в пространстве меток MPLS (SRGB или SRLB).

По возможности рекомендуется настраивать идентичные блоки SRGB на всех узлах домена SR. Это упрощает поиск неисправностей, поскольку с одним префиксом связывается одна и та же метка на всех узлах. Кроме того, это упрощает поддержку адресации anycast, как описано в параграфе 3.3.

Ниже перечислены аспекты поведения, связанные с SR на основе уровня данных MPLS.

  • Расширение сигнализации IGP для сегмента IGP-Prefix включает флаг для указания непосредственно подключенным соседям операции NEXT или CONTINUE при обработке SID. Это поведение эквивалентно Penultimate Hop Popping (NEXT) или Ultimate Hop Popping (CONTINUE) в MPLS.

  • Prefix-SID выделяется в форме метки MPLS (или индекса в SRGB), подобно выделению адреса IP. Обычно выделение Prefix-SID происходит в соответствии с политикой оператора или NMS15 и значение SID меняется очень редко.

  • Хотя SR позволяет привязать к перфиксу IGP локальный сегмент, термины «сегмент IGP-Prefix» и Prefix-SID предполагают глобальный сегмент (т. е. SID определяется из анонсируемого SRGB). Это согласуется со всеми описанными примерами использования, которые требуют привязки к префиксам IGP глобальных сегментов.

  • Процессу выделения недопустимо назначать один идентификатор Prefix-SID для разных префиксов.

  • Если узел узнает Prefix-SID со значением, выходящим за пределы локально настроенного диапазона SRGB, этому узлу недопустимо использовать Prefix-SID и следует внести в журнал запись об ошибке в конфигурации.

  • Если узел N анонсирует Prefix-SID SID-R для префикса R, который присоединен к N, и задает операцию CONTINUE для выполнения подключенными напрямую соседями, узел N должен поддерживать показанную ниже запись в FIB.

    Входящий активный сегмент: SID-R

    Входящая операция: NEXT

    Выходной интерфейс: NULL

  • Удаленный узел M должен поддерживать приведенную ниже запись FIB для любого узнанного Prefix-SID SID-R, присоединенного к R.

    Входящий активный сегмент: SID-R

    Входящая операция: Если next-hop префикса R является источником (originator) R, а M дана инструкция удалить активный сегмент, выполняется операция NEXT. В противном случае выполняется CONTINUE.

    Выходной интерфейс: Интерфейс(ы) в направлении next-hop по пути, рассчитанному с использованием алгоритма, анонсированного с SID в направлении префикса R.

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

3.1.3. SRv6

При использовании SR с уровнем данных IPv6:

  • Prefix-SID является адресом IPv6:

  • оператор должен явно создать экземпляр SRv6 SID. Адреса IPv6 по умолчанию не являются SRv6 SID.

Узел N, анонсирующий адрес IPv6 R, подходящий в качестве идентификатора сегмента, должен поддерживать приведенную ниже запись FIB.

Входящий активный сегмент: R

Входящая операция: NEXT

Выходной интерфейс: NULL

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

Независимо от поддержки SR любой удаленный узел IPv6 будет поддерживать обычную (plain) запись IPv6 FIB для любого префикса представляющего или не представляющего сегмент. Это позволяет пересылать пакеты узлу, владеющему SID, даже узлам, не поддерживающим SR.

Для SRv6 возможна поддержка множества алгоритмов. Поскольку связанные с алгоритмами SID являются просто адресами IPv6, связанные с алгоритмом записи пересылки могут быть получены путем выделение узлом связанных с алгоритмом подсетей, к которым относятся связанные с алгоритмами SID.

Не поддерживающие алгоритм узлы могут по-прежнему иметь записи FIB, включающие относящийся к алгоритму адрес, даже в тех случаях, когда данный узел не рассчитывает связанного с алгоритмом пути. Это смягчается тем, что не поддерживающие данный алгоритм узлы не будут включаться в топологию, связанную со специфичным для алгоритма SPF. Поэтому трафик для связанных с алгоритмом адресатов обычно не будет проходить через исключенный узел. Если такой трафик будет приходить на узел и пересылаться им, он будет по-прежнему продвигаться в направлении адресата. Значение next-hop будет указывать поддерживающий алгоритм узел (в этом случае пакеты будут пересылаться по связанным с алгоритмом путям или обрасываться при отсутствии таких путей) или узел который не поддерживает данный алгоритм (в этом случае пакеты будут пересылаться по путям Algorithm 0 в направлении адресата).

3.2. Сегмент IGP-Node (Node-SID)

Сегмент IGP Node-SID недопустимо связывать с префиксом, которым владеет несколько маршрутизаторов в одном домене маршрутизации.

3.3. Сегмент IGP-Anycast (Anycast-SID)

Сегмент Anycast или Anycast-SID форсирует осведомленную об ECMP пересылку в направлении ближайшего узла набора anycast. Это полезно при создании правил организации трафика на макроуровне и механизмов защиты.

Сегментам IGP-Anycast недопустимо указывать на конкретный узел.

Внутри группы anycast все маршрутизаторы домена SR должны анонсировать для одного SID один и тот же префикс.

3.3.1. Anycast-SID в SR-MPLS

                        +--------------+
                        |   Group A    |
                        |192.0.2.10/32 |
                        |    SID:100   |
                        |              |
                 +-----------A1---A3----------+
                 |      |    | \ / |   |      |
      SID:10     |      |    |  /  |   |      |     SID:30
203.0.113.1/32   |      |    | / \ |   |      |  203.0.113.3/32
       PE1------R1----------A2---A4---------R3------PE3
          \     /|      |              |      |\     /
           \   / |      +--------------+      | \   /
            \ /  |                            |  \ /
             /   |                            |   /
            / \  |                            |  / \
           /   \ |      +--------------+      | /   \
          /     \|      |              |      |/     \
        PE2------R2----------B1---B3---------R4------PE4
203.0.113.2/32   |      |    | \ / |   |      | 203.0.113.4/32
      SID:20     |      |    |  /  |   |      |     SID:40
                 |      |    | / \ |   |      |
                 +-----------B2---B4----------+
                        |              |
                        |   Group B    |
                        | 192.0.2.1/32 |
                        |    SID:200   |
                        +--------------+

Рисунок 1. Группы транзитных устройств.


На рисунке 1 показан пример сети с двумя группами транзитных устройств. Группа A включает устройства {A1, A2, A3 и A4}. Для всех этих устройств используется anycast-адрес 192.0.2.10/32 и Anycast-SID 100.

Группа B включает устройства {B1, B2, B3 и B4} с anycast-адресом 192.0.2.1/32 и Anycast-SID 200. В этой топологии каждое краевое устройство PE (Provide Edge) имеет путь в группы A и B.

PE1 может выбрать конкретную группу транзитных устройств для передачи трафика из PE3 или PE4. Это будет выполняться путем вталкивания Anycast-SID выбранной группы в стек.

Обработка anycast и последующих сегментов требует особой осторожности.

                   +-------------------------+
                   |       Group A           |
                   |     192.0.2.10/32       |
                   |        SID:100          |
                   |-------------------------|
                   |                         |
                   |   SRGB:         SRGB:   |
SID:10             |(1000-2000)   (3000-4000)|             SID:30
  PE1---+       +-------A1-------------A3-------+       +---PE3
         \     /   |    | \           / |    |   \     /
          \   /    |    |  +-----+   /  |    |    \   /
   SRGB:   \ /     |    |         \ /   |    |     \ /   SRGB:
(7000-8000) R1     |    |          \    |    |      R3 (6000-7000)
           / \     |    |         / \   |    |     / \
          /   \    |    |  +-----+   \  |    |    /   \
         /     \   |    | /           \ |    |   /     \
  PE2---+       +-------A2-------------A4-------+       +---PE4
SID:20             |   SRGB:         SRGB:   |             SID:40
                   |(2000-3000)   (4000-5000)|
                   |                         |
                   +-------------------------+

Рисунок 2. Транзитные пути через Anycast Group A.


Для случая MPLS в показанной выше топологии при необходимости передачи пакета от устройства PE1 (или PE2) устройству PE3 (или PE4) потребуется инкапсулировать пакет в данные (payload) MPLS с показанным ниже стеком меток.

  • Метка, выделенная R1 для Anycast-SID 100 (внешняя).

  • Метка, выделенная ближайшим маршрутизатором группы A для SID 30 (для получателя PE3).

В этом случае первую метку легко рассчитать. Однако по причине наличия в этой топологии более одного ближайшего устройства (A1 и A2) определение второй метки невозможно, если A1 и A2 не выделят одно и то же значение метки для одного префикса. Устройства A1 и A2 могут быть выпущены разными производителями. Если оба устройства не выделят одинаковые метки для SID 30, будет невозможно использовать anycast Group A в качестве транзитной anycast-группы в направлении PE3. Поэтому PE1 (или PE2) не сможет рассчитать подходящий стек меток для того, чтобы явно направить пакет через устройства группы A. То же самое будет происходить для устройств PE3 и PE4 при попытке передать пакет из PE1 или PE2.

Чтобы упростить использование сегмента anycast, рекомендуется настраивать идентичные блоки SRGB на всех узлах конкретной группы anycast. При использовании описанного выше метода расчет метки, следующей за сегментом anycast, становится простым.

Использование сегмента anycast без настройки одинаковых SRGB на всех узлах anycast-группы может приводить к ошибкам в маршрутизации (в среде MPLS VPN может возникать утечка трафика между VPN).

3.4. Сегмент IGP-Adjacency (Adj-SID)

Смежность формируется между локальным (т. е. анонсирующим отношения смежности в IGP) и удаленным (т. е. другой стороной отношений смежности) узлами. Локальный узел должен быть узлом IGP. Удаленный узел может быть смежным соседом IGP или несмежным соседом (например, смежность по пересылке [RFC4206]).

Пакет, инжектируемый в любой точке домена SR со списком сегментов {SN, SNL}, где SN — Node-SID узла N, SNL — Adj-SID, привязанный к N смежностью по каналу L, будет пересылаться по кратчайшему пути к N, а затем будет коммутироваться узлом N без учета кратчайшего пути IP в направлении канала L. Если Adj-SID указывает множество смежностей, узел N будут распределять трафик между элементами множества.

Аналогично при использовании глобального Adj-SID пакет, инжектированный в домен SR со списком сегментов {SNL}, где SNL -глобальный идентификатор Adj-SID, связанный узлом N со смежностью по каналу L, будет пересылаться по кратчайшему пути к N, а затем коммутироваться узлом N без учета кратчайшего пути IP в направлении канала L. Если Adj-SID указывает множество смежностей, узел N будут распределять трафик между элементами множества. Использование глобального Adj-SID позволяет уменьшить размер списка сегментов при выражении пути за счет дополнительного состояния (т. е. глобальный Adj-SID будет вставляться всеми маршрутизаторами области в их таблицы пересылки).

Сегмент IGP-Adjacency или Adj-SID форсирует коммутацию пакета от узла в направлении определенного интерфейса или набора интерфейсов. Это служит ключом к теоретическому доказательству того, что любой путь можно выразить в форме списка сегментов.

Представление Adj-SID включает набор флагов, поддерживаемых приведенную ниже функциональность.

  • Право на защиту (например, с помощью IPFRR или MPLS-FRR). Защита позволяет в случае отказа интерфейсов, связанных с Adj-SID, пересылать пакеты по другому пути. Использование защиты безусловно определяется политикой, т. е. может быть или не быть желательным.

  • Индикация локального или глобального действия Adj-SID. По умолчанию следует использовать локальную область действия.

  • Индикация сохранения Adj-SID при перезапуске уровня управления. Сохранение является ключевым атрибутом, предотвращающим SR Policy от временной некорректности пересылки в результате повторного выделения Adj-SID.

Вес (как описано ниже) также связывается с анонсом Adj-SID.

Узлу следует выделять один идентификатор Adj-SID для каждой из своих смежностей.

Узел может выделять множество Adj-SID для одной смежности. Примером является поддержка Adj-SID с желательной и нежелательной защитой.

Узел может связать одие идентификатор Adj-SID со множеством смежносетй.

Для обеспечения возможности анонсировать в IGP все идентификаторы Adj-SID, представляющие отношения смежности IGP между парой узлов, недопустимо подавление параллельных смежностей протоколом IGP.

Когда узел связывает Adj-SID V с локальным каналом данных L, он должен установить в FIB приведенную ниже запись.

Входящий активный сегмент: V

Входящая операция: NEXT

Выходной интерфейс: L

Adj-SID предполагает пересылку пакетов через указанные Adj-SID смежности от анонсирующего Adj-SID маршрутизатора независимо от стоимости IGP/SPF. Инями словами, использование сегментов смжности переопределяет решение о маршрутизации, принятое алгоритмом SPF.

3.4.1. Параллельные смежности

Adj-SID могут применяться для представления набора параллельных интерфейсов между двумя смежными маршрутизаторами.

Узел должен создать запись FIB для любого локально инициированного Adj-SID со значением W, связанного с набором каналов B.

Входящий активный сегмент: W

Входящая операция: NEXT

Выходные интерфейсы: балансировка трафика между каналами данных набора B.

Когда параллельные смежности применяются и связаны с одним Adj-SID для оптимизации функции распределения нагрузки можно связать весовой коэффициент с идентификатором Adj-SID, анонсируемым для каждой смежности. Вес указывает вход (или систему SDN/оркестроки) коэффициента загрузки для параллельных смежностей. Как показано на рисунке 3, A и B соединены двумя параллельными отношениями смежности.

      Link-1
    +--------+
    |        |
S---A        B---C
    |        |
    +--------+
      Link-2

Рисунок 3. Параллельные каналы и Adj-SID.


Ужел A анонсирует Adj-SID и весовые коэффициенты

  • Link-1: Adj-SID 1000, weight: 1

  • Link-2: Adj-SID 1000, weight: 2

Узел S получает анонсы параллельных смежностей и понимает, что путем использования Adj-SID 1000 узла A будет распределять трафик между параллельными каналами (Link-1 и Link-2) в отношении 1:2 (т. е. через Link-2 будет передаваться вдвое больше пакетов по сравнению с Link-1).

3.4.2. Сегменты смежности ЛВС

В подсетях ЛВС протоколы link-state определяют концепцию назначенного маршрутизатора (DR16 в OSPF) или назначенной промежуточной системы (DIS17 в IS-IS), которые передают лавинные рассылки в широковещательных подсетях и описывают топологию ЛВС в специальных маршрутных обновлениях (OSPF Type2 LSA или IS-IS Pseudonode LSP).

Сложность заключается в том, что каждый маршрутизатор анонсирует лишь свою связность с DR/DIS, а не каждого отдельного узла в ЛВС. Поэтому нужны дополнительные механизмы протоколов (IS-IS и OSPF) для того. Чтобы каждый маршрутизатор в ЛВС анонсировал Adj-SID, связанный с каждым соседом в LAN.

3.5. Взаимодействия между областями

В приведенном ниже примере предполагается, что все области (area) являются частями одного домена SR.

На рисунке 4 предполагается уровень управления IPv6 и уровень данных MPLS.

               !          !
               !          !
        B------C-----F----G-----K
       /       |          |     |
 S---A/        |          |     |
      \        |          |     |
       \D------I----------J-----L----Z (2001:DB8::2:1/128, Node-SID 150)
               !          !
       Area 1  ! Backbone ! Area 2
               !   area   !

Рисунок 4. Пример топологии Inter-Area.


В области 2 узел Z выделяет Node-SID 150 для своего локального префикса IPv6 2001:DB8::2:1/128.

Граничные маршрутизаторы областей (ABR18) G и J будут распространять префикс и SID в магистральную (опорную — backbone) область путем создания нового экземпляра префикса в соответствии с обычными правилами распространения между областями IGP.

Узлы C и I будут вести себя одинаково при утечке префиксов из магистральной области в область 1. Поэтому узел S будет видеть префикс 2001:DB8::2:1/128 с Prefix-SID 150, анонсируемый узлами C и I.

Следовательно, в результате Prefix-SID останется присоединенным к связанному с ним префиксу IGP через межобластной процесс, который работает в одном домене SR.

Когда узел S передает трафик по адресу 2001:DB8::2:1/128, он вталкивает Node-SID(150) в качестве активного сегмента и пересылает пакеты узлы A.

Когда пакет прибывает в ABR I (или C), ABR пересылает его в соответствии с активным сегментом Node-SID(150). Пересылка происходит через границы областей с использованием одного и того же Node-SID(150), пока пакет не попадет к получателю.

4. Сегменты BGP

Сегменты BGP могут назначаться и распространяться протоколом BGP.

4.1. Сегмент BGP-Prefix

Сегмент BGP-Prefix является сегментом BGP, присоединенным к префиксу BGP.

Сегмент BGP-Prefix является глобальным (если явно не анонсируется иное) внутри домена SR.

Сегмент BGP-Prefix в BGP является эквивалентом сегмента IGP-Prefix.

Вероятным применением сегментов BGP-Prefix является крупномасштабная «скелетообразная» топология (hyper-scale spine-leaf) без IGP, где информация о связности получается исключительно от протокола BGP [RFC7938].

4.2. Сегменты партнерства BGP

В контексте BGP EPE19, как описано в [SR-CENTRAL-EPE], поддерживающий EPE выходной узел может анонсировать сегменты, соответствующие его подключенным партнерам. Эти сегменты называются сегментами партнерства BGP или BGP peering SID. Они позволяют выражать заданные отправителем пути между доменами.

Входной граничный маршрутизатор автономной системы (AS20) может создать список сегментов для направления потока по выбранному пути внутри AS в направлении выбранного выходного граничного маршрутизатора C данной AS через конкретного партнера. Правила организации партнерства BGP, применяемые на входном узле, включают как минимум два сегмента — Node-SID выбранного выходного узла и сегмент партнерства BGP для выбранного выходного партнера или партнерского интерфейса.

Определены три типа сегментов партнерства BGP — PeerNode SID, PeerAdj SID и PeerSet SID.

  • PeerNode SID является локальным сегментом, на анонсирующем его узле BGP семантика сегмента включает:

    • операция SR: NEXT.

    • Next-Hop: подключенный партнерский узел, к которому относится сегмент.

  • PeerAdj SID является локальным сегментом, на анонсирующем его узле BGP семантика сегмента включает:

    • операция SR: NEXT.

    • Next-Hop: партнер, подключенный через интерфейс, с которым связан сегмент.

  • PeerSet SID является локальным сегментом, на анонсирующем его узле BGP семантика сегмента включает:

    • операция SR: NEXT.

    • Next-Hop: балансировка нагрузки через любой подключенный интерфейс к любому партнеру в связанной группе.

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

Расширения BGP, требуемые для сигнализации этих сегментов партнерства BGP, определены в [BGPLS-SR-EPE].

5. Сегмент привязки

Для обеспечения масштабируемости, затенения сетей и независимости служб в SR используется Binding SID (BSID). BSID связан с политикой SR Policy, экземпляр которой может включать список SID. Любые пакеты, принятые с активным сегментом, совпадающим с BSID, управляются привязанной SR Policy.

BSID может представлять собой локальный или глобальный идентификатор SID. Локальные BSID следует выделять из SRLB, глобальные должны выделяться из SRGB.

Использование BSID позволяет сохранять экземпляр политики (список SID) лишь на узлах, которым требуется наложить политику. Направление трафика узлу, поддерживающему политику, требует только наложения BSID. Если политика меняется, это означает, что менять потребуется лишь узлы, на которые наложена эта политика. На пользователей политики воздействия не оказывается.

5.1. Сегмент IGP Mirroring Context

Одним из вариантов использования сегмента привязки является поддержка для узла IGP анонсирования его способности обрабатывать трафик, исходно адресованный другому узлу IGP (отраженный узел), указанному адресом IP или Node-SID, при условии, что сегмент контекста отражения (Mirroring Context) вставляется в список сегментов до любого сегмента сервиса, который является локальным на отраженном узле.

Когда данный узел B хочет обеспечить защиту выходного узла A, он анонсирует сегмент, указывающий контекст узла A. Такой сегмент называют сегментом контекста отражения и он указывается идентификатором Mirror SID.

Mirror SID анонсируется с использованием сегмента привязки, определенного в расширениях SR IGP [ISIS-SR-EXT].

В случае отказа точка локального ремонта (PLR21), перенаправляющая трафик с A на B, вталкивает (PUSH) Mirror SID для защищенного трафика. При получении трафика с Mirror SID в качестве активного сегмента B использует этот сегмент и обрабатывает нижележащие сегменты в контексте A.

6. Групповая адресация

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

7. Взаимодействие с IANA

Документ не требует действий сос тороны IANA.

8. Вопросы безопасности

Маршрутизацию по сегментам можно применять для уровней данных MPLS и IPv6.

SR добавляет к пакету метаданные (инструкции) со списком элементов пути пересылки (например, узлов, каналов, служб и т. п.), через которые пакет должен пройти. Отмечено, что полный путь заданной отправителем маршрутизации может быть представлен одним сегментом. Это сегмент привязки — Binding SID.

По умолчанию SR работает внутри доверенного домена. Трафик должен фильтроваться на границе домена.

Важное значение имеет использование накопленного опыта для снижения риска несанкционированного доступа внутри доверенного домена. Такой опыт рассмотрен в [RFC4381] и применим как для SR-MPLS, так и для SRv6.

8.1. SR-MPLS

При использовании с уровнем данных MPLS SR не задает нового поведения и не меняет способ работы уровня данных MPLS. Поэтому с точки зрения безопасности этот документ не определяет новых механизмов на уровне данных MPLS.

SR позволяет выражать заданный отправителем путь в виде одного сегмента (Binding SID). По сравнению с RSVP-TE, где также обеспечивается возможность явной маршрутизации, нет основополагающих различий в плане предоставляемой информации. Как RSVP-TE, так и SR позволяют выразить заданный отправителем путь в одном сегменте.

Когда путь задается с использованием одной метки, синтаксис метаданных RSVP-TE [RFC3209] и SR эквивалентен.

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

Когда путь выражается с использованием стека меток, наличие у кого-либо доступа к смыслу меток (т. е., FEC22) означает знание явного пути. Для уровня данных MPLS изменение уровня данных не требуется и не происходит существенного изменения возможности. Тем не менее, использование стека меток будет расширяться.

Маршрутизаторы на границе домена SR должны фильтровать любой внешний трафик, направленный по меткам, связанным с сегментом внутри доверенного домена. Это включает метки в SRGB доверенного домена, метки в SRLB конкретного граничного маршрутизатора, а также метки, не входящие ни в один из этих блоков. Внешним считается любой трафик, полученный с интерфейса, подключенного к узлу, находящемуся за пределами доверенного домена.

С точки зрения защиты сети предполагается модель доверия, в которой любой узел, налагающий стек меток, предполагается правомочным для такой операции. Это существенно отличается от обычной практики IP с маршрутизацией по кратчайшему пути, но не имее6т принципиальных отличий от существующих методов явной маршрутизации типа RSVP-TE. По умолчанию для явной маршрутной информации недопустима утечка через границу административного домена. Расширения SR, определенные для различных протоколов, используют механизмы защиты этих протоколов типа шифрования, проверки подлинности, фильтрации и т. п.

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

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

Для уровня данных MPLS не предъявляется новых требований к имеющейся архитектуре, поскольку в MPLS уже разрешена заданная отправителем маршрутизация и создание стеков со множеством меток. А для обеспечения защиты уже используется фильтрация пакетов MPLS на границе области доверия [RFC4381], [RFC5920].

8.2. SRv6

При использовании с уровнем данных IPv6 SR добавляет заголовок SRH [IPv6-SRH] типа Routing Extension, как определено в [RFC8200].

SRH добавляет в пакет IPv6 метаданные со списком элементов пути пересылки (например, узлы, каналы, службы и т. п.), через которые пакет должен пройти, в форме адресов IPv6. Полный путь с заданной отправителем маршрутизацией может быть представлен в пакете с использованием одного сегмента (адреса IPv6).

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

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

В общем случае маршрутизатор SRv6 воспринимает и устанавливает идентификаторы сегментов (в форме адресов IPv6) только в том случае, когда SID анонсируются доверенным источником. Полученная информация проверяется с использованием имеющихся протоколов уровня управления, обеспечивающих механизмы защиты и проверки подлинности. SR не определяет дополнительных механизмов защиты к существующим протоколам уровня управления.

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

  • злонамеренные маршрутные петли;

  • обход контроля доступа;

  • сокрытие источника DoS-атаки.

Вопросы безопасности SR при использовании с уровнем данных IPv6 более подробно рассмотрены в [RFC5095]. Новый заголовок IPv6 SRH определен в [IPv6-SRH]. В этом же документе рассматриваются указанные выше проблемы безопасности.

8.3. Контроль перегрузок

SR не вносит новых требований к контролю перегрузок. По умолчанию предполагается доставка трафика в режиме best effort. Контроль перегрузок может быть реализован на оконечных точках. При использовании правил SR распределение пропускной способности может обеспечиваться на основе мониторинга входящего трафика, связанного с сегментом привязки, указывающим SR Policy. Могут применяться и другие решения типа предложенного в [RFC8084].

9. Проблемы управляемости

В сетях с поддержкой SR путь для пакета кодируется в заголовке. Поскольку путь не передается сигнальными протоколами, нужны механизмы OAM для того, чтобы операторы сетей могли проверить эффективность пути, а также отслеживать его жизнеспособность и производительность. Однако следует отметить, что SR позволяет существенно снизить число состояний на транзитных узлах, поэтому снижается и число элементов, которыми должен управлять транзитный узел.

Варианты использования SR OAM для уровня данных MPLS определены в [RFC8403], а процедуры SR OAM для MPLS — в [RFC8287].

Маршрутизаторы SR получают анонсы SID (индексы, метки или адреса IPv6) от разных протоколов маршрутизации, которые расширены для поддержки SR. Каждый из таких протоколов имеет механизмы мониторинга и поиска неполадок, обеспечивающие работу и функции управления для IP-адресов, которые должны быть расширены с целью обеспечения этих функций для SID.

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

При указании пути в виде стека меток узлам может потребоваться механизм сигнализации уровню управления своих возможностей (размера поддерживаемого стека меток).

Модель данных YANG [RFC6020] для настройки и работы SR определена в [SR-YANG].

При использовании SR с уровнем данных IPv6 сегменты указываются адресами IPv6. Выделение, управление и поиск неполадок для идентификаторов сегментов не отличаются от имеющихся механизмов, применимых к выделению и администрированию адресов IPv6.

Адрес получателя (DA) пакет задает адрес активного сегмента, а список сегментов в SRH — полный путь пакета. Проверка пригодности заданного отправителем пути выполняется путем проверки соответствия DA и SRH в пакете эквивалентным записям в таблице маршрутизации.

В контексте уровня данных SRv6 заданный отправителем путь кодируется в SRH, как описано в [IPv6-SRH]. Заданный отправителем путь SRv6 представляется в заголовке SRH в виде списка адресов IPv6, где активный сегмент указывается в поле DA заголовка IPv6. Обычно при проверке любым узлом заголовка пакета можно вывести путь source-routed, к которому пакет относится. Подобно контексту уровня данных SR-MPLS, реализация может создавать пакеты контроля пути и мониторинга, где путь source-routed помещается в SRH, а каждый сегмент пути помещает в пакет соответствующие данные для сквозного контроля пути и производительности.

10. Литература

10.1. Нормативные документы

[RFC2119] Bradner, S., «Key words for use in RFCs to Indicate Requirement Levels», BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, <https://www.rfc-editor.org/info/rfc2119>.

[RFC3031] Rosen, E., Viswanathan, A., and R. Callon, «Multiprotocol Label Switching Architecture», RFC 3031, DOI 10.17487/RFC3031, January 2001, <https://www.rfc-editor.org/info/rfc3031>.

[RFC8174] Leiba, B., «Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words», BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017, <https://www.rfc-editor.org/info/rfc8174>.

[RFC8200] Deering, S. and R. Hinden, «Internet Protocol, Version 6 (IPv6) Specification», STD 86, RFC 8200, DOI 10.17487/RFC8200, July 2017, <https://www.rfc-editor.org/info/rfc8200>.

10.2. Дополнительная литература

[BGPLS-SR-EPE] Previdi, S., Filsfils, C., Patel, K., Ray, S., and J. Dong, «BGP-LS extensions for Segment Routing BGP Egress Peer Engineering», Work in Progress, draft-ietf-idr-bgpls-segment-routing-epe-15, March 2018.

[IPv6-SRH] Filsfils, C., Ed., Previdi, S., Leddy, J., Matsushima, S., and D. Voyer, Ed., «IPv6 Segment Routing Header (SRH)», Work in Progress, draft-ietf-6man-segment-routing-header-14, June 2018.

[ISIS-SR-EXT] Previdi, S., Ed., Ginsberg, L., Ed., Filsfils, C., Bashandy, A., Gredler, H., Litkowski, S., Decraene, B., and J. Tantsura, «IS-IS Extensions for Segment Routing», Work in Progress, draft-ietf-isis-segment-routing-extensions-19, July 2018.

[OSPF-SR-EXT] Psenak, P., Previdi, S., Filsfils, C., Gredler, H., Shakir, R., Henderickx, W., and J. Tantsura, «OSPF Extensions for Segment Routing», Work in Progress, draft-ietf-ospf-segment-routing-extensions-25, April 2018.

[OSPFv3-SR-EXT] Psenak, P., Ed., Filsfils, C., Previdi, S., Ed., Gredler, H., Shakir, R., Henderickx, W., and J. Tantsura, «OSPFv3 Extensions for Segment Routing», Work in Progress, draft-ietf-ospf-ospfv3-segment-routing-extensions-13, May 2018.

[PCEP-SR-EXT] Sivabalan, S., Filsfils, C., Tantsura, J., Henderickx, W., and J. Hardwick, «PCEP Extensions for Segment Routing», Work in Progress, draft-ietf-pce-segment-routing-12, June 2018.

[RFC3209] Awduche, D., Berger, L., Gan, D., Li, T., Srinivasan, V., and G. Swallow, «RSVP-TE: Extensions to RSVP for LSP Tunnels», RFC 3209, DOI 10.17487/RFC3209, December 2001, <https://www.rfc-editor.org/info/rfc3209>.

[RFC4206] Kompella, K. and Y. Rekhter, «Label Switched Paths (LSP) Hierarchy with Generalized Multi-Protocol Label Switching (GMPLS) Traffic Engineering (TE)», RFC 4206, DOI 10.17487/RFC4206, October 2005, <https://www.rfc-editor.org/info/rfc4206>.

[RFC4381] Behringer, M., «Analysis of the Security of BGP/MPLS IP Virtual Private Networks (VPNs)», RFC 4381, DOI 10.17487/RFC4381, February 2006, <https://www.rfc-editor.org/info/rfc4381>.

[RFC4915] Psenak, P., Mirtorabi, S., Roy, A., Nguyen, L., and P. Pillay-Esnault, «Multi-Topology (MT) Routing in OSPF», RFC 4915, DOI 10.17487/RFC4915, June 2007, <https://www.rfc-editor.org/info/rfc4915>.

[RFC5095] Abley, J., Savola, P., and G. Neville-Neil, «Deprecation of Type 0 Routing Headers in IPv6», RFC 5095, DOI 10.17487/RFC5095, December 2007, <https://www.rfc-editor.org/info/rfc5095>.

[RFC5120] Przygienda, T., Shen, N., and N. Sheth, «M-ISIS: Multi Topology (MT) Routing in Intermediate System to Intermediate Systems (IS-ISs)», RFC 5120, DOI 10.17487/RFC5120, February 2008, <https://www.rfc-editor.org/info/rfc5120>.

[RFC5440] Vasseur, JP., Ed. and JL. Le Roux, Ed., «Path Computation Element (PCE) Communication Protocol (PCEP)», RFC 5440, DOI 10.17487/RFC5440, March 2009, <https://www.rfc-editor.org/info/rfc5440>.

[RFC5714] Shand, M. and S. Bryant, «IP Fast Reroute Framework», RFC 5714, DOI 10.17487/RFC5714, January 2010, <https://www.rfc-editor.org/info/rfc5714>.

[RFC5920] Fang, L., Ed., «Security Framework for MPLS and GMPLS Networks», RFC 5920, DOI 10.17487/RFC5920, July 2010, <https://www.rfc-editor.org/info/rfc5920>.

[RFC6020] Bjorklund, M., Ed., «YANG — A Data Modeling Language for the Network Configuration Protocol (NETCONF)», RFC 6020, DOI 10.17487/RFC6020, October 2010, <https://www.rfc-editor.org/info/rfc6020>.

[RFC6241] Enns, R., Ed., Bjorklund, M., Ed., Schoenwaelder, J., Ed., and A. Bierman, Ed., «Network Configuration Protocol (NETCONF)», RFC 6241, DOI 10.17487/RFC6241, June 2011, <https://www.rfc-editor.org/info/rfc6241>.

[RFC6549] Lindem, A., Roy, A., and S. Mirtorabi, «OSPFv2 Multi-Instance Extensions», RFC 6549, DOI 10.17487/RFC6549, March 2012, <https://www.rfc-editor.org/info/rfc6549>.

[RFC7938] Lapukhov, P., Premji, A., and J. Mitchell, Ed., «Use of BGP for Routing in Large-Scale Data Centers», RFC 7938, DOI 10.17487/RFC7938, August 2016, <https://www.rfc-editor.org/info/rfc7938>.

[RFC8084] Fairhurst, G., «Network Transport Circuit Breakers», BCP 208, RFC 8084, DOI 10.17487/RFC8084, March 2017, <https://www.rfc-editor.org/info/rfc8084>.

[RFC8202] Ginsberg, L., Previdi, S., and W. Henderickx, «IS-IS Multi-Instance», RFC 8202, DOI 10.17487/RFC8202, June 2017, <https://www.rfc-editor.org/info/rfc8202>.

[RFC8287] Kumar, N., Ed., Pignataro, C., Ed., Swallow, G., Akiya, N., Kini, S., and M. Chen, «Label Switched Path (LSP) Ping/Traceroute for Segment Routing (SR) IGP-Prefix and IGP-Adjacency Segment Identifiers (SIDs) with MPLS Data Planes», RFC 8287, DOI 10.17487/RFC8287, December 2017, <https://www.rfc-editor.org/info/rfc8287>.

[RFC8355] Filsfils, C., Ed., Previdi, S., Ed., Decraene, B., and R. Shakir, «Resiliency Use Cases in Source Packet Routing in Networking (SPRING) Networks», RFC 8355, DOI 10.17487/RFC8355, March 2018, <https://www.rfc-editor.org/info/rfc8355>.

[RFC8403] Geib, R., Ed., Filsfils, C., Pignataro, C., Ed., and N. Kumar, «A Scalable and Topology-Aware MPLS Data-Plane Monitoring System», RFC 8403, DOI 10.17487/RFC8403, July 2018, <http://www.rfc-editor.org/info/rfc8403>.

[SR-CENTRAL-EPE] Filsfils, C., Previdi, S., Dawra, G., Aries, E., and D. Afanasiev, «Segment Routing Centralized BGP Egress Peer Engineering», Work in Progress, draft-ietf-spring-segment-routing-central-epe-10, December 2017.

[SR-MPLS] Bashandy, A., Ed., Filsfils, C., Ed., Previdi, S., Decraene, B., Litkowski, S., and R. Shakir, «Segment Routing with MPLS data plane», Work in Progress, draft-ietf-spring-segment-routing-mpls-14, June 2018.

[SR-YANG] Litkowski, S., Qu, Y., Sarkar, P., and J. Tantsura, «YANG Data Model for Segment Routing», Work in Progress, draft-ietf-spring-sr-yang-09, June 2018.

Благодарности

Спасибо Dave Ward, Peter Psenak, Dan Frost, Stewart Bryant, Pierre Francois, Thomas Telkamp, Ruediger Geib, Hannes Gredler, Pushpasis Sarkar, Eric Rosen, Chris Bowers и Alvaro Retana за их комментарии и рецензирование документа.

Участники работы

Перечисленные ниже лица внесли существенный вклад в определение архитектуры сегментной маршрутизации и редактирование этого документа.

Ahmed Bashandy

Cisco Systems, Inc.

Email: bashandy@cisco.com

Martin Horneffer

Deutsche Telekom

Email: Martin.Horneffer@telekom.de

Wim Henderickx

Nokia

Email: wim.henderickx@nokia.com

Jeff Tantsura

Email: jefftant@gmail.com

Edward Crabbe

Email: edward.crabbe@gmail.com

Igor Milojevic

Email: milojevicigor@gmail.com

Saku Ytti

TDC

Email: saku@ytti.fi

Адреса авторов

Clarence Filsfils (редактор)

Cisco Systems, Inc.

Brussels

Belgium

Email: cfilsfil@cisco.com

Stefano Previdi (редактор)

Cisco Systems, Inc.

Italy

Email: stefano@previdi.net

Les Ginsberg

Cisco Systems, Inc.

Email: ginsberg@cisco.com

Bruno Decraene

Orange

FR

Email: bruno.decraene@orange.com

Stephane Litkowski

Orange

France

Email: stephane.litkowski@orange.com

Rob Shakir

Google, Inc.

1600 Amphitheatre Parkway

Mountain View, CA 94043

United States of America

Email: robjs@google.com

Перевод на русский язык

Николай Малых

nmalykh@gmail.com

1Segment Routing.

2Destination Address.

3Internet Engineering Task Force.

4Internet Engineering Steering Group.

5Segment Identifier.

6Virtual Machine.

7Network Configuration Protocol — протокол настройки конфигурации сети.

8Path Computation Element Communication Protocol — протокол коммуникаций между элементами расчета путей.

9SR Header.

10Traffic Engineering.

11Operations, Administration, and Maintenance — операции, администрирование, обслуживание.

12Fast Reroute.

13Shortest Path First.

14Equal Cost Multipath — множество расноценных путей.

15Network Management System — система управления сетью.

16Designated Router.

17Designated Intermediate System.

18Area Border Router.

19Egress Peer Engineering — организация исходящих партнеров.

20Autonomous System.

21Point of Local Repair.

22Forwarding Equivalence Class — класс эквивалентности пересылки.

Рубрика: RFC, SDN | Комментарии к записи RFC 8402 Segment Routing Architecture отключены

RFC 8425 IANA Considerations for IPv6 Neighbor Discovery Prefix Information Option Flags

Internet Engineering Task Force (IETF)                          O. Troan
Request for Comments: 8425                                 Cisco Systems
Updates: 4861                                                  July 2018
Category: Standards Track
ISSN: 2070-1721

IANA Considerations for IPv6 Neighbor Discovery Prefix Information Option Flags

Рекомендации IANA для флагов опции Prefix Information в IPv6 ND

PDF

Аннотация

Опция с информацией о префиксе (Prefix Information Option или PIO) в анонсах маршрутизаторов (Router Advertisement или RA) протокола обнаружения соседей IPv6 (Neighbor Discovery или ND) определяет 8-битовое поле флагов. В поле было определено 2 флага, а оставшиеся 6 битов были резервными (Reserved1). В RFC 6275 был определён флаг для этой опции без создания реестра IANA и обновления RFC 4861. Цель этого документа заключается в создании реестра IANA для флагов PIO. Документ обновляет RFC 4861.

Статус документа

Документ относится к категории Internet Standards Track.

Документ является результатом работы IETF1 и представляет согласованный взгляд сообщества IETF. Документ прошёл открытое обсуждение и был одобрен для публикации IESG2. Дополнительную информацию о стандартах Internet можно найти в разделе 2 в RFC 7841.

Информацию о текущем статусе документа, ошибках и способах обратной связи можно найти по ссылке https://www.rfc-editor.org/info/rfc8425.

Авторские права

Авторские права (Copyright (c) 2018) принадлежат IETF Trust и лицам, указанным в качестве авторов документа. Все права защищены.

К документу применимы права и ограничения, указанные в BCP 78 и IETF Trust Legal Provisions и относящиеся к документам IETF (http://trustee.ietf.org/license-info), на момент публикации данного документа. Прочтите упомянутые документы внимательно. Фрагменты программного кода, включённые в этот документ, распространяются в соответствии с упрощённой лицензией BSD, как указано в параграфе 4.e документа IETF Trust Legal Provisions, без каких-либо гарантий (как указано в Simplified BSD License).

1. Введение

Опция PIO в анонсах RA протокола IPv6 ND определяет 8-битовое поле флагов. В поле было определено 2 флага, а оставшиеся 6 битов были резервными (Reserved1). В RFC 6275 был определён флаг для этой опции без создания реестра IANA и обновления RFC 4861. Цель этого документа заключается в создании реестра IANA для флагов PIO.

2. Текущие флаги опции PIO

В настоящее время опция PPI протокола ND [RFC4861] содержит приведённые на рисунке 1, определённые в опубликованных RFC.

 0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
|L|A|R|Reserved1|
+-+-+-+-+-+-+-+-+

Рисунок 1. Флаги PIO.


L

Флаг принадлежности к каналу (On-link) [RFC4861].

A

Флаг автономной настройки адресов [RFC4861].

R

Флаг адреса маршрутизатора [RFC6275].

Reserved1

Резервные биты/

3. Обновления RFC 4861

Этот документ обновляет параграф «4.6.2. Информация о префиксе» [RFC4861] для указания реестра IANA, созданного этим документом (4. Взаимодействие с IANA).

Текущий список флагов опции PIO представлен в реестре IPv6 Neighbor Discovery Prefix Information Option Flags.

4. Взаимодействие с IANA

Агентство IANA создало новый реестр IPv6 Neighbor Discovery Prefix Information Option Flags с флагами для опции PIO. Начальное содержимое реестра представлено в таблице.

Бит опции PIO

Описание

Документ

0

L — On-link Flag

[RFC4861]

1

A — Autonomous Address Configuration Flag

[RFC4861]

2

R — Router Address Flag

[RFC6275]

3-7

Резерв

Новые флаги в заголовке опции PIO могут выделяться по процедуре Standards Action [RFC8126].

Реестр флагов доступен по ссылке <http://www.iana.org/assignments/icmpv6-parameters>.

5. Вопросы безопасности

Этот документ не связан с вопросами безопасности.

6. Нормативные документы

[RFC4861] Narten, T., Nordmark, E., Simpson, W., and H. Soliman, «Neighbor Discovery for IP version 6 (IPv6)», RFC 4861, DOI 10.17487/RFC4861, September 2007, <https://www.rfc-editor.org/info/rfc4861>.

[RFC6275] Perkins, C., Ed., Johnson, D., and J. Arkko, «Mobility Support in IPv6», RFC 6275, DOI 10.17487/RFC6275, July 2011, <https://www.rfc-editor.org/info/rfc6275>.

[RFC8126] Cotton, M., Leiba, B., and T. Narten, «Guidelines for Writing an IANA Considerations Section in RFCs», BCP 26, RFC 8126, DOI 10.17487/RFC8126, June 2017, <https://www.rfc-editor.org/info/rfc8126>.

Адрес автора

Ole Troan

Cisco Systems

Philip Pedersens vei 1

Lysaker 1366

Norway

Email: ot@cisco.com


Перевод на русский язык

Николай Малых

nmalykh@protokols.ru

1Internet Engineering Task Force.

2Internet Engineering Steering Group.

Рубрика: RFC | Оставить комментарий

Спецификация языка P4_14, версия 1.0.5

The P4 Language Specification

Version 1.0.5

Спецификация языка P4, версия 1.0.5

May 31, 2018

The P4 Language Consortium

PDF

1 Введение

P4 — это декларативный язык описания обработки пакетов в сетевых элементах пересылки, таких как коммутаторы, сетевые адаптеры (NIC), маршрутизаторы и др. Язык основан на абстрактной модели пересылки, включающей синтаксический анализатор (parser) и набор табличных ресурсов «сопоставление-действие» (СД, match+action), разделенных на входной и выходной конвейер. Анализатор идентифицирует заголовки, имеющиеся в каждом входящем пакете. Каждая таблица СД выполняет поиск по подмножеству полей заголовка и применяет действия (action), соответствующие первой подходящей (совпадающей) записи в таблице. Графическое представление этой модели дано на рисунке 1.

P4 сам по себе не зависит от протокола, но позволяет задавать протоколы плоскости пересылки. Программа P4 задает для каждого элемента пересылки:

  • определения заголовков — формат (набор полей с их размерами) каждого заголовка в пакете;

  • граф анализа — разрешенные в пакетах последовательности заголовков;

  • определения таблиц — тип выполняемого поиска, входные поля для применения, выполняемые действия, размер каждой таблицы;

  • определения действий — композитные операции, состоящие из примитивов действий;

  • схему конвейера и поток управления — набор таблиц в конвейере и порядок прохождения пакетов через конвейер.

P4 настраивает конфигурацию элементов пересылки. После настройки таблицы могут заполняться правилами обработки пакетов. Такие операции называются в этом документе операциями в процессе работы (run time). Эти операции не препятствуют изменению конфигурации работающего устройства.


Рисунок 1. Абстрактная модель пересылки.

1.1 Абстрактная модель P4

На рисунке 1 представлена высокоуровневая абстрактная модель P4. Язык P4 работает лишь с небольшим числом простых правил.

  • Для каждого пакета анализатор формирует разобранное представление (Parsed Representation), с которым работают таблицы СД.

  • Таблицы СД во входном конвейере (Ingress Pipeline) создают выходную спецификацию (Egress Specification), определяющую набор портов (и число экземпляров пакета для каждого порта), куда нужно переслать пакет.

  • Блок очередей (Queuing Mechanism) обрабатывает выходную спецификацию, создавая требуемые экземпляры пакета и представляя каждый из них выходному конвейеру (Egress Pipeline). Выходные очереди могут буферизовать пакеты при перегрузке (over-subscription) выходного порта, хотя P4 этого не требует.

  • Физический адресат (порт) экземпляра пакета определяется до попадания пакета в выходной контроллер. После передачи пакета в Egress Pipeline этот адресат не может быть сменен (хотя возможно отбрасывание пакета и дополнительные изменения заголовков).

  • По завершении обработки в выходном конвейере формируется заголовок экземпляра на основе Parsed Representation (с изменениями в процессе обработки СД) и полученный пакет передается в порт.

P4 поддерживает рециркуляцию и клонирование пакетов, которые на рисунке 1 не показаны (см. раздел 14 Рециркуляция и клонирование).

Язык P4 сосредоточен на задании анализатора, таблиц СД и управлении потоком пакетов через конвейеры. Программисты задают эти операции в программах P4, которые определяют конфигурацию коммутатора, как показано на рисунке 1.

Машина, на которой может работать программа P4, называется целевой платформой (target). Хотя платформа может напрямую выполнять программу P4, в документе предполагается компиляция программы в соответствующую конфигурацию платформы. В текущей версии P4 не раскрывает, например, функциональности блока очередей (Queuing Mechanism) и не задает семантику Egress Specification сверх упомянутой выше. В настоящее время они считаются зависящими от платформы, указанной на входе компилятора, и раскрываются вместе с другими интерфейсами, которые обеспечивают настройку конфигурации и управление в процессе работы системы. В будущих версиях P4 спецификация этих механизмов может быть раскрыта, что позволит согласованно управлять этими ресурсами из программ P4.

1.2 Пример mTag

В первой статье о P4 [1] содержится пример, названный mTag. В этой спецификации данный пример используется для разъяснения базовых функций языка. Полный код этого примера, включая run-time API, доступен на сайте P4 [2].

Рассмотрим пример сети L2 со стоечными коммутаторами (ToR1), связанными через двухуровневое ядро. Предположим, что число хостов возросло и таблицы L2 переполняются. … P4 позволяет описать решение с минимальными изменениями архитектуры сети. … Маршруты через ядро представляются 32-битовыми метками, состоящими из 4 однобайтовых полей. Такая метка может указывать маршрут, заданный отправителем (source route) … Каждому коммутатору в ядре нужно проверить лишь один байт метки и выполнить коммутацию не его основе. [1]

В примере приведены две программы P4, одна из которых предназначена для краевых коммутаторов (ToR), другая — для агрегирующих (коммутаторы ядра). Эти программы используют общие определения заголовков пакетов, синтаксических анализаторов и действий.

1.3 Абстракции P4

P4 обеспечивает перечисленные ниже абстракции, экземпляры которых включаются в программы P4.

  • Тип заголовка (Header type) — спецификация полей в заголовке.

  • Экземпляр заголовка (Header instance) — конкретный экземпляр заголовка пакета или метаданных.

  • Функция состояния анализатора (Parser state function) определяет заголовки, идентифицируемые в пакете.

  • Функция действия (Action function) состоит из примитивов действий, применяемых совместно.

  • Экземпляр таблицы (Table instance) задает поля для сопоставления и выполняемые действия.

  • Функция управления потоком (Control flow function) — императивное описание порядка применения таблиц.

  • Память состояний (Stateful memories) — счетчики, измерители и регистры, где учитываются пакеты.

В дополнение к этим абстракциям высокого уровня используются абстракции более низких уровней.

  • Для экземпляра заголовка.

    • Метаданные хранят на уровне отдельного пакета состояние, которое не выводится из данных пакета. Иногда трактуются так же, как заголовки пакета.

    • Стек заголовков — непрерывный массив экземпляров заголовков.

    • Зависимые поля — поля, значения которых зависят от расчетов, применяемых к другим полям или константам.

  • Для анализатора.

    • Набор значений (Value set) — обновляемые в процессе работы значения, определяющие смену состояний анализатора.

    • Расчеты контрольных сумм — возможность применить функцию к набору байтов из пакета и потом проверить соответствие поля повторному расчету.

1.4 Структура языка P4

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

Значения констант могут быть представлены в P4 двоичными (префикс 0b), десятичными и шестнадцатеричными (префикс 0x) значениями. Иногда требуется указывать число битов, которые следует использовать для представления значений. P4 позволяет сделать это путем добавления размера к базовой спецификации (1.5.1 Спецификации значений).

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

1.5 Используемые соглашения

В этом документе грамматические конструкции P4 представлены в формате BNF с использованием приведенных ниже соглашений:

  • для представления BNF используется зеленый цвет;
  • терминальные узлы выделены курсивом;
  • узлы, имена которых имеют суффикс _name, являются неявно строками, начинающимися с буквы (не цифры;

  • узлы, за которыми следует символ +, указывают 1 или несколько экземпляров;

  • узлы, за которыми следует символ *, указывают возможность наличия экземпляров возможно 0);

  • символ | разделяет опции, из которых нужно выбрать одну;

  • квадратные скобки [] служат для группировки узлов; группа является необязательной, если за ней не указан символ +; группа может указываться с символом * после нее, указывающим возможность наличия экземпляров;

  • символы специального назначения (например, [ ] * + |) можно применять в качестве терминальных узлов путем размещения их внутри кавычек, например, «*»;

  • остальные символы являются литералами (например, фигурные скобки, точка с запятой, круглые скобки, точка);

  • если правило не помещается в строку, новая строка с продолжением начинается сразу после символов ::=, а описание завершается пустой строкой;

  • для представления примеров используется синий цвет;

  • для выделения мест, где указан размер поля (этот размер может иметь значение), применяется узел field_value (он является синонимом для любого постоянного значения const_value).

Типы заголовков и определения таблиц задаются объявлениями, которые обычно состоят из набора пар атрибут-значение, разделенных двоеточием. Анализаторы, действия и поток управления задаются императивно с нетипизованными параметрами (если они имеются) и ограниченным набором операций.

1.5.1 Спецификации значений

Как отмечено в параграфе 1.4 Структура языка P4, язык P4 поддерживает базовые значения с возможностью указания их размера в битах. Формальное представление приведено ниже.

const_value ::= [ "+" | - ] [ width_spec ] unsigned_value
unsigned_value ::= binary_value | decimal_value | hexadecimal_value

binary_value ::= binary_base binary_digit+
decimal_value ::= decimal_digit+
hexadecimal_value ::= hexadecimal_base hexadecimal_digit+

binary_base ::= 0b | 0B
hexadecimal_base ::= 0x | 0X

binary_digit ::= _ | 0 | 1
decimal_digit ::= binary_digit | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
hexadecimal_digit ::=
	decimal_digit | a | A | b | B | c | C | d | D | e | E | f | F

width_spec ::= decimal_digit+ ’
field_value ::= const_value

За спецификацией размера следует апостроф (не обратная галочка). Размер должен указываться десятичным числом.

Отметим, что константы всегда начинаются с цифры, в отличие от идентификаторов. Элемент const_value можно читать как значение константы (constant value). Элемент field_value используется в спецификации для того, чтобы указать возможность влияния размера представления. В остальных случаях он является синонимом const_value. Пробельные символы завершают спецификацию константы.

Символы подчеркивания допускаются в значениях для группировки цифр. Например, можно задать 78_256_803 или 0b1101_1110_0101 для удобства восприятия.

Битовый размер значения может быть указан с помощью bit_width. Нулевой размер в этом случае равносилен незаданному размеру. Если размер не указан перед значением, он выводится. Для положительных значений выведенный размер равен минимальному числа битов, требуемых для представления значения, для отрицательных — на 1 больше. Отрицательные числа представляются в форме дополнения до 2 (15.7 Преобразование значений полей2).

Ниже даны примеры представления некоторых значений.

Таблица 1. Примеры представления значений.

Обозначение

Десятичное значение

Число битов

Примечания

42

42

6

По умолчанию используется десятичная форма.

16’42

42

16

То же значение с явным указанием размера (16 битов).

0b101010

42

6

Двоичное представление того же числа без явного указания размера.

0’0x2a

42

6

Нулевой размер равносилен неуказанному размеру и реальный размер выводится из значения.

12’0x100

256

12

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

7’0b1

1

7

Двоичное значение с явным указанием размера.

-0B101

-5

4

Знак не применяется до вычисления остальной части.

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

+ - * / % « » | & ˆ ∼

2 Заголовки и поля

2.1 Объявления типов заголовков

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

Типы заголовков задаются, как показано ниже (в формате BNF).

header_type_declaration ::=
	header_type header_type_name { header_dec_body }
header_dec_body ::=
	fields { field_dec + }
	[ length : length_exp ; ]
	[ max_length : const_value ; ]
field_dec ::= field_name : bit_width [ ( field_mod ) ];
field_mod ::= signed | saturating | field_mod , field_mod
length_bin_op ::= "+" | - | "*" | "<<" | ">>"
length_exp ::=
	const_value |
	field_name |
	length_exp length_bin_op length_exp |
	( length_exp )
bit_width ::= const_value | "*"

При определении заголовков используются перечисленные ниже соглашения.

  • Типы должны иметь атрибут fields.

    • Список отдельных полей упорядочивается.

    • Поля по умолчанию не имеют знака и не насыщаются (т. е. операции сложения и вычитания учитывают переход между максимум и 0).

    • Смещения битов поля от начала заголовка определяются суммой размеров предшествующих полей списка.

    • Байты упорядочиваются в соответствии с заголовком пакета.

    • Биты упорядочиваются от старшего к младшему. Таким образом, если первое поле в списке заголовка имеет размер 1, это будет старший бит первого байта в заголовке.

    • Все биты заголовка должны помещаться в то или иное поле.

    • Не более одного поля в типе заголовка может быть указано а форме *, обозначающей переменный размер.

  • Если все поля имеют фиксированный размер (нет полей *), заголовок также будет иметь фиксированный размер. В противном случае размер заголовка будет переменным

  • Атрибут length задает выражение, значением которого определяет размер заголовка в байтах (для заголовков с переменным размером).

    • Этот атрибут является обязательным для полей переменного размера (имеется поле *).

    • При наличии этого атрибута у заголовка фиксированного размера компилятор должен выдавать предупреждение.

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

  • Атрибут max_length указывает максимально разрешенный размер заголовка (переменного размера) в байтах.

    • Если в процессе работы рассчитанный размер превысит заданное значение, это считается особым случаем синтаксического анализа (см. параграф 4.6 Исключительные случаи при анализе).

    • Атрибут max_length применяется лишь для заголовков переменного размера.

    • При наличии этого атрибута у заголовка фиксированного размера компилятор должен выдавать предупреждение.

  • Порядок применения и ассоциативность операторов определяются соглашениями языка C.

P4 поддерживает заголовки переменного размера для пакетов за счет использования полей со специальным битом размера *. Размер таких полей выводится из общего размера заголовка (в байтах), указанного атрибутом length. Размер поля в битах составляет ((8 * length) — сумма размеров фиксированных полей). В заголовке разрешается наличие не более одного поля с размером *.

Ниже приведен пример объявления заголовка VLAN (802.1Q).

header_type vlan_t {
	fields {
		pcp		: 3;
		cfi		: 1;
		vid		: 12;
		ethertype	: 16;
	}
}

Типы метаданных заголовка объявляются с применением такого же синтаксиса.

header_type local_metadata_t {
	fields {
		cpu_code	: 16; 	// Код для пакетов, отправляемых в CPU
		port_type	: 4;	// Тип порта: up, down, local...
		ingress_error	: 1;	// Ошибка при проверке входного порта
		was_mtagged	: 1;	// Отслеживание помеченного (mtag) на входе пакета
		copy_to_cpu	: 1;	// Специальный код, задающий копирование в CPU
		bad_packet	: 1;	// Прочие ошибки
	}
}

2.2 Экземпляры заголовков и метаданных

Хотя объявление типа header задает тип заголовка, пакет может включать множество экземпляров данного типа. P4 требует явно объявлять каждый экземпляр до ссылок на него. Имеется два типа экземпляров заголовков — пакеты и метаданные. Обычно заголовки пакетов идентифицируются по прибытии пакетов на вход устройства, а метаданные хранят информацию о пакете, которая обычно отсутствует в данных пакета (например, входной порт или временная метка). Большая часть метаданных представляет просто состояние на уровне пакета, используемое в процессе обработки подобно регистрам. Однако некоторые метаданные могут иметь особое значение для работы коммутатора. Например, система очередей может использовать значение определенного поля метаданных при выборе очереди для пакета. P4 признает такую зависимую от платформы семантику, но не пытается ее представлять.

Заголовки пакетов (ключевое слово header) и метаданные (ключевое слово metadata) отличаются лишь их пригодностью (validity). В заголовках пакетов поддерживается отдельный индикатор пригодности, который проверяется явно, а метаданные считаются действительными всегда. Это различие дополнительно рассматривается в параграфе 2.2.1 Проверка пригодности экземпляров заголовков и метаданных. По умолчанию экземпляры метаданных инициализируются со значением 0. Форма BNF для заголовков и метаданных представлена ниже.

instance_declaration ::= header_instance | metadata_instance
header_instance ::= scalar_instance | array_instance
scalar_instance ::= header header_type_name instance_name ;
array_instance ::=
	header header_type_name
		instance_name "[" const_value "]" ;

metadata_instance ::=
	metadata header_type_name
		instance_name [ metadata_initializer ] | ;

metadata_initializer ::= { [ field_name : field_value ; ] + }

Ниже приведены некоторые замечания.

  • Только заголовки (не экземпляры метаданных) могут образовывать массивы (стеки заголовков).

  • В header_type_name должно быть имя объявленного типа заголовка.

  • Экземпляры метаданных недопустимо создавать с типом заголовка переменного размера.

  • Поля, названные в инициализаторе, должны присутствовать в списке полей типа заголовка.

  • При наличии инициализации названные поля инициализируются указанными значениями, неназванные — 0.

  • Для экземпляров заголовков компилятор должен выдавать ошибку, если общий размер всех полей в типе заголовка не является целым числом байтов. Компилятор может дополнять заголовок до целого числа байтов.

Например,

header vlan_t inner_vlan_tag;

показывает, что в Parsed Representation для пакета должно быть выделено пространство для заголовка vlan_t. Этот заголовок можно указать при синтаксическом разборе и в таблице СД по имени inner_vlan_tag.

Примером метаданных может служить

metadata local_metadata_t local_metadata;

Это указывает, что следует выделить объект типа local_metadata_t с именем local_metadata для применения в СД.

2.2.1 Проверка пригодности экземпляров заголовков и метаданных

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

Экземпляр заголовка, объявленный с ключевым словом header, является действительным, если он извлечен в процессе синтаксического анализа (4 Спецификация анализатора3) или действие делает его действительным. Поле внутри экземпляра заголовка является действительным, если действителен включающий поле экземпляр заголовка. Для экземпляра метаданных все поля являются действительными. Проверка действительности метаданных должна вызывать предупреждение компилятора и в любом случае должна возвращать значение true.

Исключение. Причину исключения проще всего понять, рассматривая случай флагов. Предположим, например, что в метаданных используется однобитовый флаг, указывающий наличие у пакета некого атрибута (например, v4 или v6 для пакета IP). Здесь нет практической разницы между флагом со значением 0 и недействительным флагом. Точно также многим «индексным» полям метаданных может присваиваться зарезервированное значение для указания их непригодности. Однако в некоторых случаях было бы полезно иметь независимый бит действительности поля метаданных и над этим следует поработать.

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

2.2.2 Стек заголовков

P4 поддерживает понятие «стека заголовков», который представляет собой последовательность смежных экземпляров однотипных заголовков. Примерами могут служить стеки меток MPLS и тегов VLAN. Стеки заголовков объявляются как массивы (см. array_instance в параграфе 2.2 Экземпляры заголовков и метаданных).

Экземпляры заголовков из стека указываются как элементы массива (в квадратных скобках) и эквивалентны не входящим в стек экземплярам. Анализатор поддерживает информацию для управления стеком заголовков.

2.3 Ссылки на заголовки и поля

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

header_ref ::= instance_name | instance_name "[" index "]"
	index ::= const_value | last

Для указания конкретного поля заголовка служат имя экземпляра и поля, разделенные точкой.

field_ref ::= header_ref . field_name

Примером может служить inner_vlan_tag.vid, где inner_vlan_tag объявлен как экземпляр заголовка типа vlan_tag.

  • Поля должны указываться в атрибуте fields при объявлении заголовка.

  • Ссылки на поля должны всегда указываться относительно родительского заголовка. Это позволяет использовать одно имя поля в разных типах заголовков без возникновения путаницы.

  • Каждый экземпляр заголовка в данный момент может быть действительным или недействительным. Это состояние может быть проверено в процессе обработки СД.

  • Ссылки на недействительный заголовок (или какое-то из его полей) в процессе работы приводят к особому неопределенному (undefined) значению, влияние которого зависит от контекста.

Чтобы помочь программистам в создании синтаксических анализаторов для стеков заголовков, P4 поддерживает два ключевых слова next и last, которые могут применяться для ссылок на экземпляры заголовков в стеке. Такие ссылки преобразуются автоматически, когда анализатор вызывает функцию extract для заголовка. Если stk является стеком заголовков, то stk[next] изначально указывает в stk заголовок с индексом 0 и автоматически перемещается при каждом вызове extract(stk[next]). Если вызов extract(stk[next]) выполняется более N раз, где N — размер стека, вычисление stk[next] ведет к исключению p4_pe_index_out_of_bounds. Ключевое слово last указывает экземпляр, на который будет указывать next перед последним возможным вызовом extract. Если такого экземпляра нет, возвращается p4_pe_index_out_of_bounds. Не допускается использование next и last за пределами анализатора.

Хотя допускается использование extract с постоянным индексом, попадающим в стек, вместе с применением next, смешивать эти режимы не рекомендуется во избежание путаницы для программистов.

2.4 Списки полей

Во многих случаях удобно указывать последовательность полей. Например, функция хэширования может принимать такую последовательность на входе или подсчет контрольной суммы может выполняться для последовательности полей. P4 поддерживает такие объявления и каждая запись в списке может указывать конкретное поле, экземпляр заголовка (это эквивалентно указанию всех полей данного заголовка) или содержать фиксированное значение. В списках могут указываться заголовки пакетов и метаданные.

field_list_declaration ::=
	field_list field_list_name {
		[ field_list_entry ; ] +
	}
field_list_entry ::=
	field_ref | header_ref | field_value | field_list_name | payload

В списке полей можно указать другой список полей. В результате имена списков полей и имена экземпляров заголовков являются частью одного пространства имен. Рекурсивные ссылки в списках не поддерживаются.

Идентификатор payload показывает включение в список полей содержимого пакета, следующего после заголовка. Это сделано для поддержки особых случаев, таких как расчет Ethernet CRC для всего пакета или контрольной суммы TCP.

3 Расчет контрольных сумм и хэш-значений

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

P4 позволяет связать функцию с набором полей и ссылаться на результат операции (отображение пакетов на целые числа) в программах P4. Эти функции называют расчетом для списка полей (field list calculations) или объектом расчета (calculation object). P4 не поддерживает задание выражений для алгоритма базовой функции, считая их примитивами действий. Для удобства задан набор известных алгоритмов.

Функция расчета для списка полей сопоставляет с пакетом целое число и может настраиваться в процессе работы через интерфейс API. Целевые платформы могут различаться в части поддержки этих интерфейсов, но обычно поддерживается задание значения «затравки» (seed), а также могут настраиваться некоторые параметры алгоритма (например, коэффициенты используемого при расчете полинома) и даже набор используемых полей.

Расчет для списка полей может быть указан как свойство расчета контрольных сумм (параграф 3.1 Контрольные суммы) или примитив действия.

field_list_calculation_declaration ::=
	field_list_calculation field_list_calculation_name {
		input {
			[ field_list_name ; ] +
		}
		algorithm : stream_function_algorithm_name ;
		output_width : const_value ;
	}

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

Значение output_width указывает выходной размер в битах.

Экземпляр поля исключается из расчета (как будто его нет в списке), если заголовок поля недействителен.

Алгоритм указывается строковым значением (string). Ниже приведен список определенных алгоритмов, но платформы могут поддерживать другие алгоритмы.

3.1 Контрольные суммы

В некоторых полях (например, контрольная сумма IP) содержится результат потокового расчета. P4 позволяет представлять такие зависимости с объявлением расчетных полей. Вычисляемые поля важны в том смысле, что они проверяются на входе и обновляются на выходе.

Синтаксис связывает последовательность директив проверки или обновления экземпляра конкретного поля и могут включать условия их применения. Первая запись, для которой условие выполняется пакетом (условие может отсутствовать) определяет привязку. Это позволяет менять расчеты на основе формата пакетов. Например, расчет контрольной суммы TCP может несколько различаться для пакетов с заголовками IPv4 и IPv6. Отметим, что условия проверяются перед выполнением операции обновления или проверки. В настоящее время поддерживается ограниченный набор условий.

calculated_field_declaration ::=
	calculated_field field_ref { update_verify_spec + }
update_verify_spec ::=
	update_or_verify field_list_calculation_name [ if_cond ] ;
update_or_verify ::= update | verify
if_cond ::= if ( calc_bool_cond )
calc_bool_cond ::=
	valid ( header_ref | field_ref ) |
	field_ref == field_value

Ниже приведен пример объявления. Предполагается, что объявления field_list_calculation для tcpv4_calc и tcpv6_calc уже заданы, а ipv4 и ipv6 являются экземплярами заголовков.

calculated_field tcp.chksum {
	update tcpv4_calc if (valid(ipv4));
	update tcpv6_calc if (valid(ipv6));
	verify tcpv4_calc if (valid(ipv4));
	verify tcpv6_calc if (valid(ipv6));
}

Для контрольный сумм вычисление по списку полей предназначено для привязки списка полей и алгоритма к конкретным экземплярам полей. Это объявление показывает, что значение, сохраненное в field_ref, предполагается значением, рассчитанным для указанного набора полей в пакете. Хотя P4 поддерживает такие объявления в любом месте программы, размещать их следует сразу после объявлений соответствующего экземпляра заголовка. Поля переменного размера (*) не разрешается объявлять в списках.

Опция verify указывает, что анализатору следует рассчитать значение для списка полей и сравнить его со значением указанного поля. При расхождении возникает исключение p4_pe_checksum (см. параграф 4.6.1 Стандартные исключения анализатора5). Эта проверка выполняется в конце синтаксического анализа и лишь при действительном field_ref.

Опция update указывает системе на необходимость обновить значение поля, если были внесены изменения в какое-либо из полей, от которых данное поле зависит. Операция обновления выполняется при выходной сборке. Если ни одно поле не изменялось, сохраняется значение из конвейера СД.

4 Спецификация анализатора

Синтаксический анализатор P4 представляется как машина состояний (конечный автомат). Он может быть представлен графом анализа, с узлами в качестве состояний и ребрами, задающими смену состояния. На рисунке 2 приведен очень простой пример. Отметим, что на этом рисунке указаны заголовки для каждого состояния. Хотя такой подход поддерживается в P4, он не является обязательным. Узел в графе анализа может быть «чистым узлом принятия решений», не связанным с конкретным экземпляром заголовка, а также возможна обработка одним узлом нескольких заголовков.

 
Рисунок 2. Простой граф анализа и граф mTag.


Ниже показаны несколько функций анализатора P4 для примера mTag. Функция start вызывает анализатор ethernet напрямую.

parser ethernet {
	extract(ethernet);	// Начало анализа с заголовка ethernet.
	return select(latest.ethertype) {
		0x8100:		vlan;
		0x800:		ipv4;
		default:	ingress;
	}
}
parser vlan {
	extract(vlan);
	return select(latest.ethertype) {
		0xaaaa:		mtag;
		0x800:		ipv4;
		default:	ingress;
	}
}
parser mtag {
	extract(mtag);
	return select(latest.ethertype) {
		0x800:		ipv4;
		default:	ingress;
	}
}

Ссылка на ingress прерывает синтаксический анализ и вызывает входную функцию потока управления.

4.1 Разобранное представление

Анализатор создает представление пакета, с которым работает этап СД. Оно называется разобранным представлением (Parsed Representation) пакета. Это набор экземпляров заголовков, которые действительны для пакета. Анализатор создает исходное разобранное представление как описано ниже. Операции СД могут менять это представление путем изменения значений полей и смены состояний пригодности для экземпляров заголовков. Последнее ведет к исключению или добавлению соответствующего заголовка.

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

Метаданные считаются частью Parsed Representation для пакета, поскольку они обычно трактуются подобно заголовкам.

4.2 Операция синтаксического анализа

Пакет передается анализатору, начиная с первого байта. Анализатор поддерживает значение текущего смещения в пакете, которое служит указателем на конкретный байт заголовка. Анализатор извлекает заголовки из пакета по текущему смещению в связанный с пакетом экземпляр заголовка (метаданные) и помечает этот экземпляр как действительный, обновляя Parsed Representation для пакета. Затем анализатор увеличивает смещение (для перехода к следующему действительному байту) и меняет свое состояние.

Программа P4 может проверять метаданные для принятия решений о смене состояния, хотя целевые платформы могут вносить ограничения для таких проверок. Например, может использоваться номер входного порта для определения начального состояния анализатора, допускающего разные форматы пакетов. Метаданные, предоставляемые клонированием или рециркуляцией точно так же можно использовать для управления поведением анализатора (см. раздел 14 Рециркуляция и клонирование).

В P4 каждое состояние представляется как функция синтаксического анализатора. Эти функции могут завершаться одним из четырех способов.

  • Оператор return, задающий имя выполняемой функции анализатора, которая служит следующим этапом обработки пакета.

  • Оператор return, задающий имя функции управления (12 Обработка пакетов и поток управления). Это прерывает процесс анализа с переходом с операции СД путем вызова указанной функции управления.

  • Явное выполнение оператора parse_error (см. параграф 4.6 Исключительные случаи при анализе).

  • Неявная ошибка анализатора (4.6.1 Стандартные исключения анализатора).

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

Определена операция select для ветвления на разных этапах обработки в зависимости от значений выражений, включающего поля или данные пакета.

Если заголовки нужно извлечь при входе в то или иное состояние, это указывается явно путем вызова функции extract (4.5 Функция extract1) в начале определения функции анализатора (4 Спецификация анализатора2).

4.3 Наборы значений

В некоторых случаях значение, определяющее переход анализатора из одного состояния в другое, нужно определять в процессе работы. Примером может служить MPLS, где значение метки определяет, какой заголовок следует после поля метки MPLS и это может динамически меняться в процессе работы. Для поддержки нужной функциональности в P4 служат наборы значений анализатора (Parser Value Set). Это именованные наборы значений с run-time API для добавления и удаления значений из набора. Имя набора можно указывать в условиях смены состояний анализатора.

Value Set содержат лишь значения, но не типы заголовков или информацию о смене состояния. Все значения в наборе должны соответствовать одному переходу состояния. Например, все метки MPLS, соответствующие переходу к IPv4, должны присутствовать в одном наборе, а метки для перехода к IPv6 — в другом. Наборы меток объявляются на верхнем уровне программы P4 за пределами функций анализатора и используют одно глобальное пространство имен. Наборы значений следует определять до их указания в функциях анализатора.

value_set_declaration ::= parser_value_set value_set_name;

Размер набора выводится из того места, где этот набор упомянут. Если набор значений применяется неоднократно и для него будет выводиться разный размер, компилятор должен сообщать об ошибке.

Интерфейс run-time API для обновления наборов значений анализатора должен разрешать пары «значение-маска», задаваемые совместно.

4.4 BNF для функций анализатора

Ниже представлена форма BNF для объявления функций анализатора.

parser_function_declaration ::=
	parser parser_state_name { parser_function_body }

parser_function_body ::=
	extract_or_set_statement*
	return_statement

extract_or_set_statement ::= extract_statement | set_statement
extract_statement ::= extract ( header_extract_ref );
header_extract_ref ::=
	instance_name |
	instance_name "[" header_extract_index "]"

header_extract_index ::= const_value | next

set_statement ::= set_metadata ( field_ref, metadata_expr ) ;
metadata_expr ::= field_value | field_or_data_ref

return_statement ::=
	return_value_type |
	return select ( select_exp ) { case_entry + }

return_value_type ::=
	return parser_state_name ; |
	return control_function_name ; |
	parse_error parser_exception_name ;

case_entry ::= value_list : case_return_value_type ;
value_list ::= value_or_masked [ , value_or_masked ]* | default

case_return_value_type ::=
	parser_state_name |
	control_function_name |
	parse_error parser_exception_name
value_or_masked ::=
	field_value | field_value mask field_value | value_set_name

select_exp ::= field_or_data_ref [, field_or_data_ref] *
field_or_data_ref ::=
	field_ref |
	latest.field_name |
	current( const_value , const_value )

Функция extract может извлекать лишь заголовки пакетов, но не метаданные. Функция select принимает разделенный запятыми список полей и выполняет для них конкатенацию, помещая левое значение в старшие биты объединенного значения. Операция select затем сравнивает значения в порядке из указания в программе для обнаружения совпадений. Оператор mask служит для указания троичного сопоставления (ternary) с использованием заданной маски. Сравнение выражения select со значением case используется лишь для указанных маской битов, т. е. для выражения select и значения поочередно выполняется операция AND с mask, а затем происходит сравнение.

Поддержка сравнений с маской и наборов значений может давать более одного совпадения. Предпочтение определяется порядком case (предпочтительным будет первое совпадение.

Ссылка на заголовок latest относится к извлеченному последним экземпляру заголовка в функции анализа. Использование такой формы без предшествующей операции extract в той же функции является ошибкой.

Ссылка на поле current(…) позволяет анализатору указать биты, которые еще не разобраны по полям. Первый аргумент задает смещение в битах от текущей позиции, а второй аргумент — число битов. Результат трактуется как целое число без знака с указанным размером. Он преобразуется в поле метаданных в соответствии с правилами, описанными в приложении 15.7 Преобразование значений полей.

Указанное в операторе set_metadata поле должно относиться к экземпляру метаданных. Если размер значения отличается от размера целевого поля метаданных, выполняется преобразование в соответствии с приложением 15.7 Преобразование значений полей.

4.5 Функция extract

Функция extract принимает в качестве параметра экземпляр заголовка (это не могут быть метаданные). Извлекается копия данных из пакета по текущему смещению с переносом указателя в конец данного заголовка. Отметим использование специального идентификатора next (а не last) для стека заголовков, поскольку извлечение выполняется в следующее доступное свободное место.

4.6 Исключительные случаи при анализе

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

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

Существует множество условий, при которых распознаваемые P4 ошибки могут возникать неявно. Кроме того, программист может указывать такие ошибки, как исключительная ситуация parse_error, в функции синтаксического анализатора. Оба эти варианта обрабатываются однотипно. Обработчик исключительных ситуаций в синтаксическом анализаторе можно объявить в программе, как показано ниже. Может использоваться набор метаданных, за которым следует возврат в функцию управления или отбрасывание пакета. Отметим, что установка метаданных будет давать эффект лишь при выполнении оператора return.

parser_exception_declaration ::=
	parser_exception parser_exception_name {
		set_statement *
		return_or_drop ;
	}
return_or_drop ::= return_to_control | parser_drop
return_to_control ::= return control_function_name

4.6.1 Стандартные исключения анализатора

В таблице 2 приведен список имен исключительных (особых) ситуаций при синтаксическом анализе. Идентификаторы событий имеют префикс pe (parser exception — особый случай при анализе).

Таблица 2. Стандартные исключения синтаксического анализатора.

Идентификатор

Событие

p4_pe_index_out_of_bounds

Индекс стека заголовков выходит за объявленные границы.

p4_pe_out_of_packet

В пакете недостаточно байтов для выполнения операции извлечения (extract).

p4_pe_header_too_long

Рассчитанный размер заголовка превышает заявленный максимум.

p4_pe_header_too_short

Рассчитанный размер заголовка меньше минимального размера фиксированной части заголовка.

p4_pe_unhandled_select

Для оператора select не задан принятый по умолчанию вариант, а значение выражения отсутствует в списке вариантов.

p4_pe_checksum

Обнаружена ошибка в контрольной сумме.

p4_pe_default

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

При передаче исключения конвейеру СД тип исключения указывается в метаданных (6 Стандартные внутренние метаданные).

5 Сборка пакета

На выходе элемент пересылки преобразует разобранное представление пакета (обновленное в СД) в последовательный поток байтов для передачи. Этот процесс называется сборкой (deparsing), поскольку он в некотором смысле является обращением синтаксического анализа. В P4 применяется подход, в соответствии с которым, любой формат, который следует генерировать на выходе, должен быть представлен анализатором, используемым на входе. Таким образом, граф анализа, представленный в программе P4, служит для определения алгоритма, используемого при создании пакета из Parsed Representation. Отметим несколько важных моментов:

  • при сборке используются лишь действительные (valid) заголовки;

  • если граф анализа является ациклическим, может быть реализовано топологическое упорядочение (т. е. линейный порядок в соответствии с порядком графа анализа), которое может служить для определения порядка заголовков при сборке;

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

  • поля метаданных не включаются в сборку напрямую (поскольку они не анализируются), но могут копироваться в поля заголовков пакета при обработке СД, что позволяет учесть их в выходном пакете.

6 Стандартные внутренние метаданные

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

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

Стандартные внутренние метаданные (Standard Intrinisic Metadata) названы так потому, что они устанавливаются автоматически (например, ingress_port) или требуются для описания работы абстрактной машины (например, egress_port). В таблице 3 приведены поря, определенные для экземпляров standard_metadata.

Таблица 3. Поля Standard Intrinisic Metadata.

Поле

Описание

ingress_port

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

packet_length

Число байтов в пакете. Для кадров Ethernet поле CRC не учитывается. Устанавливается до анализа. Не может применяться в сопоставлении или указываться в действиях, если коммутатор работает в режиме cut-through. Доступно лишь для чтения.

egress_spec

Задает выходной порт. Не определено до установки операцией СД в процессе входной обработки. Может указывать физический порт, логический интерфейс (туннель, LAG, маршрут, VLAN) или multicast-группу.

egress_port

Физический порт для передачи экземпляра пакета. Значение определяется блоком буферизации и поэтому действительно лишь в выходных СД (см. раздел 13 Выбор выходного порта, репликация, очередь). Доступно лишь для чтения.

egress_instance

Неанализируемый идентификатор для обозначения экземпляров пакета. Как и для egress_port, значение определяется блоком буферизации и поэтому действительно лишь в выходных СД (см. раздел 13 Выбор выходного порта, репликация, очередь). Доступно лишь для чтения.

instance_type

Указывает тип экземпляра пакета (normal, ingress clone, egress clone, recirculated, resubmitted). Представление данных зависит от платформы.

parser_status

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

parser_error_location

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

Платформы могут предоставлять свои определения внутренний метаданных, но зависящие от таких определений программы могут терять переносимость. В документе [3] указаны поля внутренний метаданных, поддерживаемые прототипом платформы BMv2 simple_switch.

7 Счетчики, измерители и регистры

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

В этом разделе отдельный счетчик, измеритель или регистр рассматриваются как «ячейка» памяти. В P4 память состояний реализована в форме именованного массива таких ячеек, имеющих один тип. Ячейки указываются именем и индексом. Чтение и обновление содержимого ячеек могут выполнять действия, применяемые таблицей. Целевые платформы могут вносить ограничения на объем вычислений при определении индекса для доступа к ячейке, а также ограничивать операции обновления содержимого ячеек. Например,

counter ip_pkts_by_dest {
	type : packets;
	direct : ip_host_table;
}

объявляет набор счетчиков, связанных с таблицей ip_host_table. Выделяется одна ячейка счетчика для каждой записи таблицы. В другом примере

meter customer_meters {
	type : bytes;
	instance_count : 1000;
}

объявляется массив из 1000 измерителей, названный customer_meters. Эти измерители можно указать из любого действия любой таблицы (хотя обычно это будут делать 1 — 2 таблицы).

P4 позволяет глобальный доступ к памяти состояний (из любой таблицы) или статические обращения с привязкой к одному экземпляру таблицы. Обычно записи одной или разных таблиц могут обращаться к одной ячейке. Это называется непрямым доступом (indirect access). P4 поддерживает также прямой доступ (direct access) к ресурсам памяти состояний, привязанным к одной таблице с выделением ячейки для каждой записи таблицы. Примером этого могут служить счетчики, связанные с отдельной записью таблицы.

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

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

7.1 Счетчики

Формат объявления счетчиков показан ниже.

counter_declaration ::=
	counter counter_name {
		type : counter_type ;
		[ direct_or_static ; ]
		[ instance_count : const_expr ; ]
		[ min_width : const_expr ; ]
		[ saturating ; ]
	}
counter_type ::= bytes | packets | packets_and_bytes
direct_or_static ::= direct_attribute | static_attribute
direct_attribute ::= direct : table_name
static_attribute ::= static : table_name

Атрибут min_width указывает минимальное число битов, требуемых для каждой ячейки. Компилятор или целевая платформа при этом могут создавать ячейки большего размера.

Атрибут saturating показывает, что счетчик будет прекращать подсчет при достижении максимального значения (в соответствии с реальным размером ячейки). Если этот атрибут не установлен, счетчик будет работать в кольцевом режиме (wrap).

Если счетчик объявлен с атрибутом direct, с каждой записью указанной таблицы связывается ячейка счетчика. В этом случае не требуется операции по учету для действия таблицы и счетчик обновляется автоматически при каждом применении записи. В результате имена счетчиков с атрибутом direct становятся недоступными для примитива count и компилятор должен выдавать ошибку при ссылках на такие счетчики.

В API, используемых в процессе работы, следует указывать действительный размер счетчика. Это требуется для определения максимального значения счетчика, необходимого для контроля насыщения счетчика или перехода от максимума в 0.

Если счетчик объявлен без атрибута direct, действия должны указывать его по имени и индексу.

Если счетчик объявлен с атрибутом static, ресурс счетчика выделяется для указанной таблицы. Компилятор должен возвращать ошибку при обнаружении ссылки на такой счетчик из действий другой таблицы.

Атрибут instance_count указывает число создаваемых экземпляров (ячеек) счетчика. Этот атрибут требуется для счетчиков без атрибута direct. Компилятор должен возвращать ошибку при объявлении счетчика с обоими атрибутами instance_count и direct или при отсутствии обоих атрибутов.

Счетчик типа bytes инкрементируется на размер пакета в байтах неявно (direct) или явно (static). Счетчик типа packets инкрементируется на 1 при каждом действии, выполняемом для этого счетчика. Счетчик типа packets_and_bytes фактически состоит из двух счетчиков, которые инкрементируются на размер пакета или 1.

7.2 Измерители

Объявление измерителя имеет показанную ниже форму, похожую на объявление счетчика.

meter_declaration ::=
	meter meter_name {
		type : meter_type ;
		[ result : field_ref ; ]
		[ direct_or_static ; ]
		[ instance_count : const_expr ; ]
	}
meter_type ::= bytes | packets

Измерители являются объектами с состоянием (stateful), измеряющими скорость данных числом пакетов или байтов в секунду и выводящими результат в форме одного из трех «цветов» (красный, желтый, зеленый), представляемых 2-битовым полем. Представление «цвета» зависит от платформы, однако предполагается, что каждая платформа определяет константы METER_COLOR_RED, METER_COLOR_YELLOW и METER_COLOR_GREEN, которые понятны компилятору и могут применяться в переносимых программах P4.

Спецификация P4 не задает конкретных алгоритмов измерения для реализации измерителей, поэтому описание семантики цветов выходит за рамки P4. Хотя алгоритмы трехцветной маркировки, заданные в RFC 2697 и RFC 2698, являются хорошими примерами, возможны и другие варианты. Конфигурация измерителей также зависит от платформы и не определяется в P46.

Если измеритель объявлен с атрибутом direct, ячейка измерителя связывается с каждой записью указанной таблицы. В таких случаях не требуется операции meter для действия таблицы и измеритель будет обновляться автоматически при каждом обращении к соответствующей записи таблицы, а результат измерения («цвет») будет храниться в поле, заданном атрибутом result. Атрибут result является обязательным для измерителей с атрибутом direct, а ссылки на такие измерители недопустимы в примитивах execute_meter и компилятор должен сообщать об ошибке при обнаружении таких ссылок.

Если измеритель объявлен с атрибутом static, его можно указывать лишь в действиях, вызываемых соответствующей таблицей через примитив execute_meter. Компилятор должен выдавать сообщение об ошибке при вызове такого измерителя из действия другой таблицы.

Атрибут instance_count указывает число выделяемых экземпляров (ячеек) измерителя и требуется для измерителей без атрибута direct.

7.3 Регистры

Регистры представляют собой память состояний и их значения доступны для считывания и записи из действий. Регистры похожи на счетчики, но могут использоваться для хранения состояний в более общем смысле. Простым примером может служить проверка обнаружения «первого пакета» определенного типа потока. Ячейка регистра выделяется для потока и инициализируется пустой (clear). Когда протокол сообщает о «первом пакете», таблица будет соответствовать этому значению (пустому) и обновит ячейку потока до состояния «активный» (marked). Следующие пакеты потока будут сопоставляться с той же ячейкой и текущее значение ячейки будет сохраняться в метаданных для пакета, а следующая таблица может убедиться, что поток был помечен как активный.

Объявление регистра похоже на объявления счетчиков и измерителей. Регистры объявляются с атрибутом width, указывающим число битов в каждой ячейке.

register_declaration ::=
	register register_name {
		width_declaration ;
		[ direct_or_static ; ]
		[ instance_count : const_value ; ]
		[ attribute_list ; ]
	}
width_declaration ::= width : const_value ;
attribute_list ::= attributes : attr_entry
attr_entry ::= signed | saturating | attr_entry , attr_entry

Атрибут instance_count указывает число экземпляров (ячеек), создаваемых для регистра. Этот атрибут требуется для регистров без атрибута direct.

Доступ к регистрам возможен с помощью примитивов register_read и register_write, описанных ниже.

8 Таблицы Match+Action (СД)

P4 позволяет задавать экземпляры таблиц с помощью объявления таблиц. Объявление задает точный набор полей, которые следует проверять при сопоставлении. С каждой записью таблицы связывается действие, выполняемое при совпадении (соответствии записи).

Если совпадения не найдено в таблице (miss), применяется заданное по умолчанию действие.

Каждая запись таблицы «сопоставление-действие (СД, match+action) имеет перечисленные ниже компоненты.

  • Значения для сопоставления с разобранным представлением (Parsed Representation) пакета. Формат этих значений задает объявление таблицы.

  • Ссылка на функцию действия (action), выполняемого при совпадении. Набор разрешенных действий задается в объявлении таблицы.

  • Значения параметров, передаваемые действию при вызове его функции. Формат параметров определяется конкретной функцией, выбранной для записи.

9 Действия

В P4 действия объявляются как функции, имена которых используются при заполнении таблиц при работе для выбора связанных с записями таблицы действий. Эти действия называют составными действиями (compound action), чтобы отличить от примитивов, если различие не очевидно из контекста.

Функции действий принимают параметры. Передаваемые параметрам значения программируются в записи таблицы с помощью run-time API. Когда запись при сопоставлении соответствует пакету, заданные параметры передаются действию. Объявления таблиц P4 могут использоваться для генерации run-time API, которые будут иметь параметры, соответствующие параметрам действия в записи. Обычно компилятор принимает на себя ответственность за корректное сопоставление этих значений в run-time API и программе P4.

В дополнение к значениям из соответствующей записи таблицы действие имеет доступ к заголовкам и метаданным из Parsed Representation.

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

Ниже приведены две функции из примера mTag. Первая функция задает отправку копии пакета в CPU. Параметры cpu_code и bad_packet раскрываются API и устанавливаются в соответствии со значениями, представленными при добавлении записи в таблицу.

// Отправка копии пакета в CPU.
action common_copy_pkt_to_cpu(cpu_code, bad_packet) {
	modify_field(local_metadata.copy_to_cpu, 1);
	modify_field(local_metadata.cpu_code, cpu_code);
	modify_field(local_metadata.bad_packet, bad_packet);
}

Эта функция устанавливает тег mTag и вызывается только на краевых коммутаторах.

// Добавление в пакет тега mTag и выбор выходной спецификации по up1.
action add_mTag(up1, up2, down1, down2) {
	add_header(mtag);
	// Копирование VLAN ethertype в mTag
	modify_field(mtag.ethertype, vlan.ethertype);
	// Установка VLAN ethertype для сигнализации mTag
	modify_field(vlan.ethertype, 0xaaaa);
	// Добавление в тег информации о заданной отправителем маршрутизации
	modify_field(mtag.up1, up1);
	modify_field(mtag.up2, up2);
	modify_field(mtag.down1, down1);
	modify_field(mtag.down2, down2);
	// Установка выходного порта для получателя по тегу
	modify_field(standard_metadata.egress_spec, up1);
}

9.1 Примитивы действий

P4 включает набор стандартных примитивов действий (операций). Конкретная платформа может поддерживать дополнительные примитивы действий. Способ раскрытия этих дополнительных примитивов FE-компилятору для семантической проверки выходит за рамки спецификации.

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

В таблице приведена краткая сводка стандартных примитивов действий, а более подробные описания даны ниже.

Таблица 4. Примитивы действий.

Имя в API

Описание

add_header

Добавляет заголовок в представление разобранного пакета (Parsed Representation).

copy_header

Копирует один экземпляр заголовка в другой.

remove_header

Помечает экземпляр заголовка как недействительный (invalid).

modify_field

Задает значение поля в представлении разобранного пакета (Parsed Representation).

add_to_field

Прибавляет значение к полю.

add

Складывает два значения и помещает результат в поле.

subtract_from_field

Вычитает значение из поля.

subtract

Вычитает одно значение из другого и помещает результат в поле.

modify_field_with_hash_based_offset

Выполняет расчет для списка полей и использует результат для генерации величины смещения.

modify_field_rng_uniform

Генерирует случайное значение из заданного диапазона и помещает результат в поле.

bit_and

Выполняет побитовую операцию И (AND) для двух значений и помещает результат в поле.

bit_or

Выполняет побитовую операцию ИЛИ (OR) для двух значений и помещает результат в поле.

bit_xor

Выполняет побитовую операцию Исключительное-ИЛИ (XOR) для двух значений и помещает результат в поле.

shift_left

Выполняет операцию сдвига dst = value1 << value2.

shift_right

Выполняет операцию сдвига dst = value1 >> value2.

truncate Выполняет отсечку пакета на выходе.

drop

Отбрасывает пакет (во входном конвейере).

no_op

Пустая операция.

push

Проталкивает все экземпляры заголовков «вниз» по массиву (стеку) и добавляет новый заголовок на вершину.

pop

Выталкивает заголовок с вершины массива (стека), перемещая оставшиеся заголовки на одну позицию вверх.

count

Обновляет значение счетчика.

execute_meter

Выполняет операцию измерения.

register_read

Считывание указанного индексом экземпляра регистра и запись полученного значения в поле.

register_write

Запись значения в указанный индексом регистр.

generate_digest

Генерация дайджеста (подписи) пакета и отправка принимающему.

resubmit

Повторное представление исходного пакета с метаданными синтаксическому анализатору.

recirculate

Повторное представление обработанного пакета.

clone_ingress_pkt_to_ingress

Передача копии исходного пакета синтаксическому анализатору. Псевдоним clone_i2i.

clone_egress_pkt_to_ingress

Передача копии обработанного пакета синтаксическому анализатору. Псевдоним clone_e2i.

clone_ingress_pkt_to_egress

Передача копии исходного пакета механизму буферизации (Buffer Mechanism). Псевдоним clone_i2e.

clone_egress_pkt_to_egress

Передача копии обработанного пакета механизму буферизации (Buffer Mechanism). Псевдоним clone_e2e.

Типы параметров действий указаны в таблице.

Таблица 5. Примитивы действий.

Обозначение

Описание

HDR

Литеральное имя экземпляра заголовка.

ARR

Имя массива экземпляров заголовков без индекса.

FLD

Ссылка на поле в представлении разобранного пакета (Parsed Representation) в форме header_instance.field_name

FLDLIST

Экземпляр списка полей, объявленного с field_list.

VAL

Промежуточное значение или значение из параметров действия в записи таблицы. Во втором случае представляется как параметр включающей функции (см. примеры ниже).

C-REF

Имя массива счетчиков (определяется при компиляции).

M-REF

Имя массива измерителей (определяется при компиляции).

R-REF

Имя массива регистров (определяется при компиляции).

FLC-REF

Ссылка на расчет для списка полей (определяется при компиляции).

Ниже приведены спецификации API для стандартных примитивов действий.

add_header(header_instance)

Добавляет заголовок в представление проанализированного пакета (Parsed Representation).

header_instance

(HDR) Имя добавляемого экземпляра заголовка.

Для указанного экземпляра заголовка устанавливается бит valid. Если заголовок был недействительным, все его поля инициализируются значением 0, а для действительного ранее заголовка поля сохраняются.

copy_header(destination, source)

Копирует один экземпляр заголовка в другой.

destination

(HDR) Имя целевого экземпляра заголовка.

source

(HDR) Имя исходного экземпляра заголовка.

Все поля копируются из заголовка source в заголовок destination. Если исходный заголовок недействителен, destination также станет недействительным. Экземпляры source и destination должны быть однотипными.

remove_header(header_instance)

Помечает заголовок как недействительный (invalid).

header_instance

(HDR) Имя удаляемого экземпляра заголовка.

Указанный заголовок помечается как недействительный и становится недоступным для последующих этапов СД (match+action), а также не будет преобразовываться в последовательность (serialize) на выходе. Все поля экземпляра заголовка становятся неинициализированными.

modify_field(dest, value [, mask] )

Устанавливает значение заданного поля в представлении проанализированного пакета (Parsed Representation).

dest

(FLD) Имя изменяемого поля заголовка (получатель).

value

(VAL или FLD) Устанавливаемое значение (источник).

mask

(VAL) Необязательная маска для указания изменяемых битов.

Обновляет значение указанного поля. В качестве параметра value может служить:

  • непосредственное значение (число);
  • значение из параметров действия в совпадающей записи (в этом случае используется имя параметра из включающей его функции);
  • ссылка на поле Parsed Representation.

Этот примитив позволяет программисту копировать одно поле в другое. Если размер, значение или маска источника больше поля dest, старшие биты источника отсекаются. Если размер источника меньше размера получателя, значение будет расширено с учетом знака. Если родительский экземпляр заголовка недействителен, операция приведет к неопределенному значению dest. При наличии маски выполняется операция (current_value & ∼ mask) | (value & mask). При отсутствии маски устанавливаются все биты получателя.

add_to_field(dest, value)

Добавляет значение к полю.

dest

(FLD) Имя изменяемого поля заголовка (получатель).

value

(VAL или FLD) Устанавливаемое значение (источник).

Значение поля dest обновляется путем сложения со значением параметра value, которым может служить параметр таблицы, непосредственное значение или ссылка на поле (см. modify_field). Если value является ссылкой на поле недействительного заголовка, значение dest становится неопределенным. Логическое поведение описано в параграфе 9.1.1 Назначение полей и атрибуты насыщения. Если value содержит непосредственное значение, оно может быть отрицательным.

add(dest, value1, value2)

Складывает value1 и value2, сохраняя сумму в dest.

dest

(FLD) Имя изменяемого поля (получатель).

value1

(VAL или FLD) Первое слагаемое.

value2

(VAL или FLD) Второе слагаемое.

В поле dest записывается сумма двух параметров value, каждый из которых может быть параметром таблицы, непосредственным значением или ссылкой на поле (см. modify_field). Если любой из параметров value является ссылкой на поле недействительного заголовка, значение dest становится неопределенным. Логическое поведение описано в параграфе 9.1.1 Назначение полей и атрибуты насыщения. Если value содержит непосредственное значение, оно может быть отрицательным.

subtract_from_field(dest, value)

Вычитает значение из поля.

dest

(FLD) Имя изменяемого поля заголовка (получатель).

value

(VAL или FLD) Вычитаемое значение.

Значение поля dest обновляется путем вычитания значения параметра value, которым может служить параметр таблицы, непосредственное значение или ссылка на поле (см. modify_field). Если value является ссылкой на поле недействительного заголовка, значение dest становится неопределенным. Логическое поведение описано в параграфе 9.1.1 Назначение полей и атрибуты насыщения. Если value содержит непосредственное значение, оно может быть отрицательным.

subtract(dest, value1, value2)

Вычитает value2 из value1 и записывает результат в поле dest.

dest

(FLD) Имя изменяемого поля (получатель).

value1

(VAL или FLD) Уменьшаемое значение.

value2

(VAL или FLD) Вычитаемое значение.

В поле dest записывается разность (value1 — value2) двух параметров value, каждый из которых может быть параметром таблицы, непосредственным значением или ссылкой на поле (см. modify_field). Если любой из параметров value является ссылкой на поле недействительного заголовка, значение dest становится неопределенным. Логическое поведение описано в параграфе 9.1.1 Назначение полей и атрибуты насыщения. Если value содержит непосредственное значение, оно может быть отрицательным.

modify_field_with_hash_based_offset(dest, base, field_list_calc, size)

Рассчитывает хэш-значение для списка полей.

dest

(FLD) Имя изменяемого поля (получатель).

base

(VAL) База для сложения с хэш-значением.

field_list_calc

(FLC-REF) Используемый для расчета метод.

size

(VAL) Размер диапазона хэш-значений (должен быть положительным числом).

Выполняется расчет хэш-значения для списка полей. Результат лежит в диапазоне base — (base + size — 1) и рассчитывается как (base + (hash_value % size)). Результат расчета можно применять в качестве дайджеста (подписи) длинного ключа (например, кортежа с 5 элементами) или смещения (индекса) для ссылки на массив регистров. При записи результата в dest выполняется обычное преобразование значений.

Если любое из полей для field_list_calc относится к недействительному заголовку, это поле исключается из списка при расчете хэш-значения.

modify_field_rng_uniform(dest, lower_bound, upper_bound)

Генерирует случайное значение из заданного диапазона.

dest

(FLD) Имя изменяемого поля (получатель).

lower_bound

(VAL или FLD) Нижняя (включительная) граница диапазона.

upper_bound

(VAL или FLD) Верхняя (включительная) граница диапазона.

Случайное значение выбирается из диапазона [lower_bound — upper_bound] и записывается в dest. Платформы могут вносить ограничения для lower_bound и upper_bound, например, требовать lower_bound = 0 и upper_bound = 2n — 1.

Если любой из параметров lower_bound или upper_bound является ссылкой на поле недействительного заголовка, значение dest будет неопределенным.

bit_and(dest, value1, value2)

Выполняет побитовую операцию AND (И) для двух параметров.

dest

(FLD) Имя изменяемого поля (получатель).

value1

(VAL или FLD) Первый параметр.

value2

(VAL или FLD) Второй параметр.

Значение поля dest обновляется результатом побитовой операции AND для значений value1 и value2, каждое из которых может быть параметром таблицы, непосредственным значением или ссылкой на поле (см. modify_field). Если любой из параметров value является ссылкой на поле недействительного заголовка, значение dest становится неопределенным. Целевые платформы могут требовать одинакового размера dest, value1 и value2.

bit_or(dest, value1, value2)

Выполняет побитовую операцию OR (ИЛИ) для двух параметров.

dest

(FLD) Имя изменяемого поля (получатель).

value1

(VAL или FLD) Первый параметр.

value2

(VAL или FLD) Второй параметр.

Значение поля dest обновляется результатом побитовой операции OR для значений value1 и value2, каждое из которых может быть параметром таблицы, непосредственным значением или ссылкой на поле (см. modify_field). Если любой из параметров value является ссылкой на поле недействительного заголовка, значение dest становится неопределенным. Целевые платформы могут требовать одинакового размера dest, value1 и value2.

bit_xor(dest, value1, value2)

Выполняет побитовую операцию XOR (Исключительное-ИЛИ) для двух параметров.

dest

(FLD) Имя изменяемого поля (получатель).

value1

(VAL или FLD) Первый параметр.

value2

(VAL или FLD) Второй параметр.

Значение поля dest обновляется результатом побитовой операции XOR для значений value1 и value2, каждое из которых может быть параметром таблицы, непосредственным значением или ссылкой на поле (см. modify_field). Если любой из параметров value является ссылкой на поле недействительного заголовка, значение dest становится неопределенным. Целевые платформы могут требовать одинакового размера dest, value1 и value2.

shift_left(dest, value1, value2)

Выполняет побитовый сдвиг влево параметра value1 на value2 позиций.

dest

(FLD) Имя изменяемого поля (получатель).

value1

(VAL или FLD) Значение для сдвига.

value2

(VAL или FLD) Размер сдвига (положительное значение).

Поле dest получает результат сдвига value1 << value2. Каждый из параметров может быть параметром таблицы, непосредственным значением или ссылкой на поле (см. modify_field). Если любой из параметров value является ссылкой на поле недействительного заголовка, значение dest становится неопределенным. Параметр value2 должен иметь положительное значение.

shift_right(dest, value1, value2)

Выполняет побитовый сдвиг вправо параметра value1 на value2 позиций.

dest

(FLD) Имя изменяемого поля (получатель).

value1

(VAL или FLD) Значение для сдвига.

value2

(VAL или FLD) Размер сдвига (положительное значение).

Поле dest получает результат сдвига value1 >> value2. Каждый из параметров может быть параметром таблицы, непосредственным значением или ссылкой на поле (см. modify_field). Если любой из параметров value является ссылкой на поле недействительного заголовка, значение dest становится неопределенным. Параметр value2 должен иметь положительное значение.

truncate(length)

Отсекает пакет на выходе.

length

(VAL) Задает число передаваемых байтов.

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

Обычно (но не обязательно) это действие применяется в выходном конвейере.

drop()

Задает отбрасывание пакета на выходе.

Указывает, что пакет не следует передавать. Примитив предназначен для выходного конвейера, где он является единственным способом указать, что передавать пакет не следует. Во входном конвейере этот примитив эквивалентен установке в метаданных egress_spec значения drop (зависит от платформы).

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

no_op()

Пустая операция.

Никаких действий по отношению к пакету не выполняется и поток управления продолжается в соответствии с текущей функцией.

push(array, count)

Проталкивает имеющиеся в массиве (стеке) заголовки «вниз» и добавляет в начало (на вершину) новые действительные заголовки.

array

(ARR) Имя изменяемого экземпляра массива.

count

(VAL) Число вталкиваемых в массив элементов.

Этот примитив служит для инициализации элементов на вершине стека заголовков. Имеющиеся элементы смещаются на count позиций в стеке, т. е. элемент с индексом N получит индекс N+count и в стек будет добавлено count действительных элементов с индексами от 0 до count-1. Примитив не меняет размер массива и элементы, индекс которых выходит за предел размера массива, будут потеряны.

pop(array, count)

Выталкивает экземпляры заголовков из начала массива (вершины стека), перемещая оставшиеся в массиве заголовки вверх.

array

(ARR) Имя изменяемого экземпляра массива.

count

(VAL) Число выталкиваемых из массива элементов.

Этот примитив служит для удаления (выталкивания) элементов из стека заголовков. Элемент с индексом N перемещается в позицию N-count, а элементы с индексами от 0 до count-1 удаляются из массива (теряются). Пустые элементы в конце массива становятся недействительными. Выталкивание элементов из пустого массива или выталкивание большего числа элементов, нежели имеется в стеке, приводит к возврату пустого массива.

count(counter_ref, index)

Обновляет значение счетчика.

counter_ref

(C-REF) Имя массива счетчиков.

index

(VAL) Смещение изменяемого счетчика в массиве.

Значение счетчика пакетов увеличивается на 1, а счетчика байтов — на размер пакета. Массив счетчиков определяется в момент компиляции. Индекс массива может быть параметром записи таблицы или определяться в момент компиляции. Ссылка на массив счетчиков с прямым отображением в этом примитиве является ошибкой.

execute_meter(meter_ref, index, field)

Выполняет операцию измерения и записывает результат в указанное параметром поле.

meter_ref

(M-REF) Имя массива измерителей.

index

(VAL) Смещение экземпляра измерителя в массиве (применимо только для измерителей типа indirect).

field

(FLD) Поле для записи результата измерения.

Выполняется операция измерения, указанная параметрами meter_ref и index. Для прямых измерителей (тип direct) параметр index игнорируется, поскольку нужную ячейку определяет запись таблицы. Размер пакета передается измерителю. Примитив обновляет состояние измерителя и полученные данные («цвет» пакета) возвращаются в параметре field. Если field относится к недействительному заголовку, состояние измерителя обновляется, но после этого отбрасывается.

register_read(dest, register_ref, index)

Читает данные из регистра.

dest

(FLD) Имя экземпляра поля для записи значения из регистра (получатель).

register_ref

(R-REF) Имя массива регистров.

index

(VAL) Смещение регистра в массиве (применимо лишь к регистрам типа indirect).

Значение регистра, указанного параметрами register_ref и index, считывается и помещается в поле dest. Для регистров с прямым доступом (тип direct) параметр index не принимается во внимание, поскольку ячейка определяется записью таблицы.

register_write(register_ref, index, value)

Записывает значение в регистр.

register_ref

(R-REF) Имя массива регистров.

index

(VAL) Смещение регистра в массиве (применимо лишь к регистрам типа indirect).

value

(VAL или FLD) Записываемое в регистр значение.

Значение параметра value записывается в регистр, указанный параметрами register_ref и index. Параметр value может быть параметром таблицы, непосредственным значением или ссылкой на поле (см. modify_field). Для регистров с прямым доступом параметр index не принимается во внимание, поскольку ячейка определяется записью таблицы.

generate_digest(receiver, field_list)

Создает дайджест пакета и передает ее получателю.

receiver

(VAL) Неанализируемый (opaque) идентификатор получателя.

field_list

(FLDLIST) Список полей, включаемых в дайджест.

Указанный список полей заполняется данными из пакета и отправляется зависимым от платформы механизмом агенту, способному обработать такой объект. Описание возможных получателей выходит за рамки спецификации P4. Примером такого получателя может служить CPU (передача по каналу, используемому для передачи пакетов) или сопроцессор, подключенный к специальной шине.

Эту функцию можно применять также для операций самообновления, таких как изучение адресов (address learning).

resubmit(field_list)

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

field_list

(FLDLIST) Список ссылок на поля метаданных.

Примитив применяется только во входном конвейере и помечает пакет для повторного представления анализатору. Входная обработка помеченного пакета выполняется до завершения конвейера с целью заполнения требуемых полей метаданных. В конце конвейера данные исходного пакета представляются заново синтаксическому анализатору вместе со значениями полей из field_list, установленными в процессе обработки. Эти значения переопределяют исходные метаданные, созданные инициализатором при объявлении экземпляра. В параметре field_list могут указываться лишь поля метаданных (но не заголовка). При неоднократном вызове примитива применяется лишь список полей из последнего действия resubmit и повторно представляется лишь один пакет.

В представленном повторно пакете устанавливается instance_type для индикации повтора (см. раздел 14 Рециркуляция и клонирование).

recirculate(field_list)

На выходе помечает пакет для повторного представления синтаксическому анализатору.

field_list

(FLDLIST) Список ссылок на поля метаданных.

Примитив применяется только в выходном конвейере и помечает пакет для повторной обработки (рециркуляции). Выходная обработка пакета выполняется до завершения конвейера и сборки пакета, после чего собранный заново пакет передается анализатору вместе с метаданными из field_list (на момент завершения выходной обработки). Эти значения метаданных переопределяют исходные метаданные, созданные инициализатором при объявлении экземпляра. В параметре field_list могут указываться лишь поля метаданных (но не заголовка). При неоднократном вызове примитива применяется лишь список полей из последнего действия recirculate и повторно представляется лишь один пакет.

В представленном повторно пакете устанавливается instance_type для индикации повтора (см. раздел 14 Рециркуляция и клонирование).

clone_ingress_pkt_to_ingress(clone_spec, field_list)

Создает копию исходного пакета и представляет ее входному анализатору.

clone_spec

(VAL) Неанализируемый (opaque) идентификатор, задающий дополнительные параметры клонирования.

field_list

(FLDLIST) Список ссылок на поля метаданных.

Это действие указывает коммутатору создание копии исходного пакета (до изменений, внесенных таблицами СД) и ее представление анализатору в виде независимого экземпляра пакета. Действие может выполняться сразу при вызове примитива или откладываться до буферизации исходного пакета. Обработка исходного пакета продолжается независимо от клона.

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

В клонированном экземпляре устанавливается поле instance_type для указания клона.

Поля метаданных, указанные в field_list (со значениями на момент завершения входной обработки) копируются в Parsed Representation экземпляра клона. Эти значения метаданных переопределяют исходные метаданные, созданные инициализатором при объявлении экземпляра (до синтаксического анализа). В параметре field_list могут указываться лишь поля метаданных (но не заголовка).

Этот примитив также имеет псевдоним clone_i2i (см. раздел 14 Рециркуляция и клонирование).

clone_egress_pkt_to_ingress(clone_spec, field_list)

Создает дубликат выходного пакета и представляет его анализатору.

clone_spec

(VAL) Неанализируемый (opaque) идентификатор, задающий дополнительные параметры клонирования.

field_list

(FLDLIST) Список ссылок на поля метаданных.

Пакет помечается для клонирования на выходе. После завершения обработки исходного пакета в выходном конвейере копия собранного заново пакета (с учетом всех изменений, внесенных таблицами СД) передается синтаксическому анализатору как независимый экземпляр пакета. Обработка исходного пакета продолжается обычным путем.

Параметр clone_spec позволяет задать зависящие от платформы характеристики операции клонирования, как указано для clone_ingress_pkt_to_ingress.

Поля метаданных, указанные в field_list (со значениями на момент завершения выходной обработки) копируются в экземпляр клона. Эти значения метаданных переопределяют исходные метаданные, созданные инициализатором при объявлении экземпляра (до синтаксического анализа). В параметре field_list могут указываться лишь поля метаданных (но не заголовка). В клонированном экземпляре устанавливается поле instance_type для указания клона.

Этот примитив также имеет псевдоним clone_e2i (см. раздел 14 Рециркуляция и клонирование).

clone_ingress_pkt_to_egress(clone_spec, field_list)

Создает копию исходного пакета и передает ее механизму буферизации (Buffering Mechanism).

clone_spec

(VAL) Неанализируемый (opaque) идентификатор, задающий дополнительные параметры клонирования.

field_list

(FLDLIST) Список ссылок на поля метаданных.

Это действие указывает коммутатору создать копию исходного пакета. Когда функция выходного потока управления начнет обработку клона, поля из field_list будут инициализированы значениями, которые имели метаданные в момент завершения функции входного потока управления для исходного пакета. В параметре field_list могут указываться лишь поля метаданных (но не заголовка).

Клон представляется напрямую механизму буферизации как независимый экземпляр пакета без обработки таблицами входного конвейера. Обработка исходного пакета продолжается обычным путем.

Параметр clone_spec позволяет задать зависящие от платформы характеристики клонирования, как указано для clone_ingress_pkt_to_ingress. В дополнение к другим атрибутам сессии clone_spec определяет стандартные метаданные egress_spec, представляемые механизму буферизации.

В клонированном экземпляре устанавливается поле instance_type для указания клона.

Этот примитив также имеет псевдоним clone_i2e (см. раздел 14 Рециркуляция и клонирование).

clone_egress_pkt_to_egress(clone_spec, field_list)

Дублирует выходную версию пакета и представляет ее механизму буферизации.

clone_spec

(VAL) Неанализируемый (opaque) идентификатор, задающий дополнительные параметры клонирования.

field_list

(FLDLIST) Список ссылок на поля метаданных.

Пакет помечается для клонирования на выходе. По завершении обработки исходного пакета в выходном конвейере пакет и его Parsed Representation для заголовков (включая все изменения в таблицах СД) вместе с полями метаданных field_list (с учетом выходной обработки) представляются механизму буферизации как новый пакет. Обработка исходного пакета продолжается обычным путем. В параметре field_list могут указываться лишь поля метаданных (но не заголовка).

Параметр clone_spec позволяет задать зависящие от платформы характеристики операции клонирования, как указано для clone_ingress_pkt_to_ingress. В дополнение к другим атрибутам сессии clone_spec определяет стандартные метаданные egress_spec, представляемые механизму буферизации.

В клонированном экземпляре устанавливается поле instance_type для указания клона.

Этот примитив также имеет псевдоним clone_e2e (см. раздел 14 Рециркуляция и клонирование).

9.1.1 Назначение полей и атрибуты насыщения

Напомним, что при объявлении поля могут быть указаны атрибуты знака и насыщения, от которых зависит логика поведения add_to_field, как показано ниже для поля без знака.

tmp = field + value
if (field.saturating && tmp < field.min)
	field = field.min
else if (field.saturating && tmp > field.max)
	field = field.max
else
	field = tmp % 2field.width

где

  • field.saturating — логическое значение, указывающее насыщение поля;

  • field.min — минимальное разрешенное значение, определяемое размером поля и наличием знака;
  • field.max — максимальное разрешенное значение, определяемое размером поля и наличием знака;
  • field.width — число битов в поле.

9.1.2 Привязка параметров

В некоторых из описанных выше примитивов параметры могут иметь разные формы:

  • непосредственное значение;
  • значение из данных параметра действия в записи таблицы;
  • ссылка на экземпляр поля, значение которого будет использовано.

Язык P4 не задает ограничений на выбор между этими формами. Однако следует отметить качественные различия (в части разных функциональных требований к базовой платформе) между указанием конкретного экземпляра поля в программе P4 и возможностью run-time API задавать экземпляр поля для ссылки при добавлении записи в таблицу. Это вопрос привязки и в первом случае привязка выполняется в момент компиляции, а второй вариант позволяет привязывать значения в процессе работы. Платформы могут ограничивать гибкость привязки параметров. Различие должно отражаться в генерируемых интерфейсах run-time API.

9.2 Определение действий

Формат объявления действий показан ниже.

action_function_declaration ::=
	action action_header { action_statement * }
action_header ::= action_name "(" [ param_list ] ")"
param_list ::= param_name [, param_name]*
action_statement ::= action_name "(" [ arg [, arg]* ] ")" ;
arg ::= param_name | field_value | field_ref | header_ref

Ссылки на счетчики, измерители и регистры указываются с помощью индексов и передаются в аргументе param_name или field_value.

Объявление функции действия должно следовать приведенным ниже соглашениям.

  • Все параметры, указанные в action_header, являются обязательными. Необязательных параметров не поддерживается.
  • Тело функции содержит лишь:
    • вызовы примитивов действий;
    • вызовы функций других действий;
    • рекурсия не поддерживается.

В приведенном ниже примере параметры dst_mac, src_mac и vid раскрываются через runtime API для добавления записей в таблицу, использующую действие. Значения, передаваемые в API, будут установлены в таблице и могут быть переданы действию для пакетов, соответствующих записи.

action route_ipv4(dst_mac, src_mac, vid) {
	modify_field(ethernet.dst_addr, dst_mac);
	modify_field(ethernet.src_addr, src_mac);
	modify_field(vlan_tag.vid, vid);
	add_to_field(ipv4.ttl, -1);
}

9.2.1 Семантика последовательных и параллельных операций

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

modify_field(hdr.fieldA, 1);
modify_field(hdr.fieldB, hdr.fieldA);

Предположим, что hdr.fieldA начинается со значения 0. Возникает вопрос — какое значение будет иметь hdr.fieldB после выполнения этого набора инструкций? При последовательной обработке по завершении первого оператора fieldA будет иметь значение 1 и второй оператор передаст это значение в поле fieldB. При параллельном исполнении обработка обоих операторов начнется одновременно, поэтому hdr.fieldA во второй инструкции будет иметь значение 0 (поскольку оно еще не изменено) и hdr.fieldB также получит значение 0.

P4 предполагает последовательное выполнение для всех примитивов действий, выполняемых в результате совпадения в данной таблице. Выполнение действий из разных таблиц также происходит последовательно и порядок операций определяется потоком управления, как описано в разделе 12 Обработка пакетов и поток управления.

10 Объявление профиля действий

В некоторых экземплярах значения параметров действий (action) не специфичны для совпадающей записи и могут совместно использоваться несколькими записями. Это можно выразить в P4 с помощью профилей действий, которые представляют собой объявляемую структуру, задающую список возможных действий, а также могущую включать иные атрибуты.

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

Вместо статической привязки одной записи из профиля действий к каждой записи таблицы сопоставления, можно связать несколько записей из профиля действий с одной записью таблицы сопоставления и позволить системе (т. е. логике плоскости данных) динамически связывать одну из записей профиля действий с каждым классом пакетов. Такое поведение включается атрибутом dynamic_action_selection. При задании этого атрибута записи профиля действий могут собираться в группы в процессе работы, а запись таблицы сопоставления можно связать с группой записей профиля действий. Для задания конкретного механизма плоскости данных, выбирающего определенную запись профиля действий в группе, нужно предоставить селектор действий. Этот селектор выбирает конкретную запись профиля действий для каждого пакета (псевдо)случайно или предсказуемо на основе полей заголовка и/или метаданных.

Ниже представлено определение профиля действий в формате BNF.

action_profile_declaration ::=
	action_profile action_profile_name {
		action_specification
		[ size : const_expr ; ]
		[ dynamic_action_selection : selector_name ; ]
	}
action_specification ::=
	actions { [ action_name ; ] + }
action_selector_declaration ::=
	action_selector selector_name {
		selection_key : field_list_calculation_name ;
}

Профили действий задаются и применяются в соответствии с приведенным ниже соглашением.

  • Атрибут size указывает число записей, требуемых для профиля действий. Если заданный размер не поддерживается, при обработке объявления будет выдан сигнал об ошибке. При опущенном атрибуте размера нет гарантии создания нужного числа записей в профиле действий в процессе работы.

11 Объявления таблиц

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

Объявление таблицы задает список полей, используемых для сопоставления с пакетами. Это могут быть ссылки на заголовки, бит действительности (valid) заголовка, или маскируемое поле заголовка. Маски в объявлении таблиц не следует путать с масками троичного сопоставления (ternary), они применяются к полю статически до операций поиска в таблице. Отметим, что поля сопоставления (ключи поиска) могут указываться в объявлении таблицы с масками. Это позволяет выполнять поиск в таблице по субполям, а не только по целому полю. Эти маски предназначены для таблиц с сопоставлением exact, позволяя в синтаксисе троичное сопоставления, хотя это является функционально избыточным.

Сопоставление всегда выполняется для конъюнкции (операция AND) всех полей ключа поиска, заданных в определении таблицы.

Ниже приведено объявление таблицы в формате BNF.

table_declaration ::=
	table table_name {
		[ reads { field_match + } ]
		table_actions
		[ min_size : const_value ; ]
		[ max_size : const_value ; ]
		[ size : const_value ; ]
		[ support_timeout : true | false ; ]
	}
field_match ::= field_or_masked_ref : field_match_type ;
field_or_masked_ref ::=
	header_ref | header_ref "." valid | field_ref | field_ref mask const_value
field_match_type ::= exact | ternary | lpm | range | valid
table_actions ::=
	action_specification | action_profile_specification
action_profile_specification ::=
	action_profile : action_profile_name ;

Приведенный ниже пример взят из программы краевого коммутатора mTag, где адрес получателя L2 из пакета отображается на mTag. Если отображения не удается найти, пакет может копироваться в CPU.

// Если в пакет нужно добавить mtag выполняется операция добавления тега.
table mTag_table {
	reads {
		ethernet.dst_addr	: exact;
		vlan.vid		: exact;
	}
	actions {
		add_mTag;	// Действие вызывается для добавления mtag.
		common_copy_pkt_to_cpu; // При отсутствии mtag пакет передается CPU
		no_op;
	}
	max_size	: 20000;

Реализация ECMP с использованием профиля действий рассмотрена в параграфе 15.8.3 Пример выбора ECMP.

Типы сопоставления описаны ниже.

exact

Значение поля должно точно совпадать со значением в таблице.

ternary

Для каждой записи в таблице предоставляется маска, которая применяется к сравниваемому полю до сравнения (операция AND). В результате совпадением считается соответствие битов, заданных маской. Поскольку такое сопоставление может давать несколько записей, для записей с сопоставлением ternary нужно задавать приоритет.

lpm

Максимально длинное совпадение префикса, которое является частным случаем сопоставления ternary, где маска содержит непрерывную последовательность 1 в старших битах и 0 в младших. Размер совпадающего префикса определяется числом единиц в маске и это число служит приоритетом для записи.

range

Каждая запись содержит минимальное и максимальное значение диапазона для соответствия записи таблицы (границы включаются в диапазон). Для определения порядка служит подпись поля.

valid

Этот тип сопоставления применим лишь для полей заголовков и экземпляров заголовков, но не для метаданных. В таблице должно быть указано значение true (соответствует действительному полю или заголовку) или false (соответствует недействительному полю или заголовку).

При объявлении и применении таблиц используются приведенные ниже соглашения.

  • Ссылки на заголовки для сопоставления могут применяться только в сопоставлениях типа valid.

  • При обработке пакета будет применяться в точности одна операция, указанная в action_specification или action_profile_specification.

    • Записи включаются в таблицу в процессе работы и каждое правило задает единственное действие в случае соответствия.

    • Действия в списке могут быть примитивами или составными (композитными).

  • В процессе работы операция вставки записи в таблицу (не часть кода P4) должна задавать:

    • значения всех полей, указываемых в операции чтения (reads);

    • имя действия из action_specification или the action_profile_specification, а также параметры, передаваемые используемой действием функции.

  • Используемое по умолчанию действие при отсутствии совпадающей записи. Это действие задается в процессе работы. Если такое действие не указано и соответствующей ключу записи не найдено в таблице, пакет остается без изменений и обработка продолжается в соответствии с потоком управления.

  • Если операция чтения (reads) не применяется, таблица всегда будет использовать принятое по умолчанию действие. Если такое действие не задано, таблица не будет воздействовать на пакет.

  • Может использоваться ключевое слово mask для сопоставления лишь некоторых битов поля. Маска применяется однократно к полю проанализированного представления (Parsed Representation) до операций сопоставления (в отличие от масок в записях, которые могут различаться у разных записей).

  • Сопоставление valid показывает, что родительский заголовок поля (или само поле в случае метаданных) проверяется на действительность. Значение 1 будет соответствовать действительному полю, 0 — недействительному. Отметим, что поля метаданных всегда действительны.

  • Атрибут min_size указывает минимальное число записей, которые нужны в таблице. Если это не поддерживается, разбор объявления таблицы будет давать ошибку.

  • Атрибут max_size указывает максимальное число записей, которые предполагаются в таблице. Если в процессе работы достигнут максимум, новая операция вставки записи может быть отвергнута.

  • Атрибут size эквивалентен заданию одинаковых значений min_size и max_size.

  • Хотя атрибуты size и min_size не обязательны, отсутствие любого из них может приводить к пропуску (исключению) таблицы компилятором в соответствии с другими требованиями.

  • Атрибут support_timeout служит для контроля устаревания таблицы. Он не обязателен и по умолчанию таблица не стареет (false).

Примитив действия no-op определен в параграфе 9.1 Примитивы действий и может применяться для записей, которым не нужно менять пакет.

12 Обработка пакетов и поток управления

Пакет обрабатывается цепочкой таблиц «сопоставление-действие (СД, match+action). В процессе настройки поток управления (порядок применения таблиц) может быть выражен императивной программой, которая может применять таблицы, вызывать другие функции потока управления и проверять условия.

Выполнение таблиц задается инструкциями apply, которые сами по себе могут воздействовать на поток управления, к которому относится пакет, путем задания набора блоков управления, один из которых выбирается для выполнения. Выбор такого блока может определяться действием для пакета или найденным для пакета совпадением.

Инструкции apply могут применяться в трех режимах:

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

  • выбор действия, где выполненное действие определяет следующий блок применяемых инструкций;

  • проверка совпадения или отсутствия, результат которой определяет следующий выполняемый блок.

Ниже приведены примеры каждого из режимов в формате BNF. В комбинациями с блоками if-else это обеспечивает механизм задания потока управления.

control_function_declaration ::=
	control control_fn_name control_block
control_block ::= { control_statement * }
control_statement ::=
	apply_table_call |
	apply_and_select_block |
	if_else_statement |
	control_fn_name ( ) ;

apply_table_call ::= apply ( table_name ) ;

apply_and_select_block ::= apply ( table_name ) { [ case_list ] }
case_list ::= action_case + | hit_miss_case +
action_case ::= action_or_default control_block
action_or_default ::= action_name | default
hit_miss_case ::= hit_or_miss control_block
hit_or_miss ::= hit | miss

if_else_statement ::=
	if ( bool_expr ) control_block
	[ else_block ]
else_block ::= else control_block | else if_else_statement
bool_expr ::=
	valid ( header_ref ) | bool_expr bool_op bool_expr |
	not bool_expr | ( bool_expr ) | exp rel_op exp | true | false

exp ::=
	exp bin_op exp | un_op exp | field_ref |
	value | ( exp )

bin_op ::= "+" | "*" | - | "<<" | ">>" | \& | "|" | ^
un_op ::= ~ | -
bool_op ::= or | and
rel_op ::= > | >= | == | <= | < | !=

Во многих случаях удобно задавать последовательность полей. Например, порядок выполнения и ассоциативность операторов соответствуют соглашениям языка C. Как указано в параграфе 4.2 Операция синтаксического анализа, анализатор возвращает имя функции управления для начала обработки СД. По завершении обработки пакет передается механизму управления очередями (если пакет не отбрасывается). При извлечении пакета из очереди выполняется выходная функция (egress), если она задана. Затем пакет передается в выходной порт, указанный полем метаданных egress_port field.

Таблицы вызываются для пакета с помощью оператора apply, как описано в начале этого раздела. Если одна таблица вызывается неоднократно в потоке управления, эти вызовы относятся к одному экземпляру таблицы, т. е. одному набору статистики, счетчиков, измерителей и операций СД для таблицы. Платформы могут вносить ограничения для вызовов таблиц, такие как запрет рекурсии, которые позволяют указывать таблицы и вызывать функции потока управления лишь однократно.

Простейшим примером потока управления является вызов цепочки таблиц с помощью оператора apply.

// Функция управления входным конвейером
control ingress {
	// Проверка согласованности mTag и порта
	apply(check_mtag);
	apply(identify_port);
	apply(select_output_port);
}

Оператор apply можно использовать для управления потоком инструкций на основе результатов поиска совпадений в таблице. Это осуществляется путем выполнения заключенного в скобки блока, следующего за оператором apply в для совпадающей (или miss) метки в блоке выбора. Программа mTag включает приведенный ниже пример.

apply(egress_meter) {
	hit { // При совпадении во входной таблице измерителей применяется правило
		apply(meter_policy);
	}
}

Кроме того, оператор apply позволяет управлять потоком инструкций на основе действия, применяемого таблицей к пакету. Например,

apply(routing_table) {
	ipv4_route_action { // Используется действие IPv4 
		apply(v4_rpf);
		apply(v4_acl);
	}
	ipv6_route_action { // Используется действие IPv6
		apply(v6_option_check);
		apply(v6_acl);
	}
	default { // используется иное действие
		if (standard_metadata.ingress_port == 1) {
			apply(cpu_ingress_check);
		}
	}
}

Отметим, что эти два режима (выбор совпадения или действия) нельзя смешивать. Они различаются потому, что зарезервированные слова hit и miss нельзя использовать в качестве имен функций для действий.

13 Выбор выходного порта, репликация, очередь

В P4 поле метаданных egress_spec служит для указания получателя или получателей пакета. Кроме того, для устройств, поддерживающих очереди, egress_spec может указывать связанную с каждым адресатом очередь. Значение egress_spec может представлять физический или логический (туннель, LAG, VLAN) порт или multicast-группу.

P4 предполагает, что механизм буферизации реализует функцию, сопоставляющую egress_spec с набором экземпляров пакета, представляемых триплетом (packet, egress_port, egress_instance). Механизм буферизации отвечает за создание экземпляров пакета вместе с полями метаданных и подобающую отправку в выходной порт через выходные таблицы СД.

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

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

Одна копия каждого пакета проходит через входной конвейер (Ingress Pipeline). По завершении входной обработки коммутатор определяет очередь (очереди) для размещения пакета на основе значения egress_spec. Пакет, имеющий множество адресатов, может быть помещен в несколько очередей.

При извлечении пакета из очереди он передается выходному конвейеру (Egress Pipeline) функцией управления выходом. Для каждого адресата в Egress Pipeline передается отдельная копия пакета, что требует репликации пакета механизмом буферизации. Физический выходной порт уже известен на момент извлечения пакета из очереди и его идентификатор передается через выходной конвейер как неизменяемое поле метаданных egress_port. Для поддержки передачи множества копий пакета в один физический порт (например, при наличии множества VLAN на порту), неизменяемое поле метаданных egress_instance содержит уникальный идентификатор для каждой копии. Семантика egress_instance зависит от платформы.

14 Рециркуляция и клонирование

Многие стандартные сетевые функции, такие как «зеркалирование» и рекурсивная обработка пакета, требуют более сложных примитивов для установки и проверки значений полей. Для поддержки таких операций в P4 имеются примитивы действий, которые позволяют организовать рециркуляцию (возврат в начало конвейера обработки) и клонирование (создание дополнительного экземпляра) пакетов. Отметим, что клонирование не является механизмом, который обычно используется для групповых пакетов (multicast). Предполагается, что обработка групповых пакетов обычно выполняется механизмом буферизации (Buffering Mechanism) вместе с выходным конвейером (13 Выбор выходного порта, репликация, очередь).

Приведенная ниже таблица 6 содержит набор операций. Первые 4 операции (префикс clone) создают полностью новый экземпляр пакета. Две последних операции работают с исходным пакетом, не создавая новых пакетов.

Таблица 6. Примитивы клонирования и рециркуляции.

Имя примитива

Источник

Место вставки

clone_ingress_pkt_to_ingress

Исходный входной пакет

Входной анализатор

clone_egress_pkt_to_ingress

Пакет после сборки

Входной анализатор

clone_ingress_pkt_to_egress

Исходный входной пакет

Механизм буферизации

clone_egress_pkt_to_egress

Пакет после сборки

Механизм буферизации

resubmit

Исходный входной пакет

Входной анализатор

recirculate

Пакет после сборки

Входной анализатор

14.1 Клонирование

Операции clone создают новый экземпляр пакета, а обработка исходного пакета продолжается как обычно. Термин «клонирование» (вместо «отражения» — mirror) для подчеркивания того, что это действие (action) отвечает лишь за создание копии пакета. «Отражение» требует дополнительной настройки, а механизм клонирования может иметь дополнительные применения.

Источником для клонирования может быть исходный экземпляр пакета (клонирование во входном конвейере) или выходящий из коммутатора пакет (клонирование на выходе). Обработка нового экземпляра может ограничиваться выходным конвейером (клон на выход) или выполняться с самого начала (клон на вход). В результате возникает 4 разных варианта, которые различаются значением поля метаданных instance_type.

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

14.1.1 Клонирование на вход


Рисунок 3. Клонирование на вход.


На рисунке 3 показаны пути пакетов, клонированных во входной конвейер. Источником пакета может быть входной или выходной конвейер.

14.1.2 Клонирование на выход

Рисунок 4. Клонирование на выход.


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

Поскольку блоку буферизации нужна спецификация выхода (metadata.egress_spec) для управления обработкой пакета, эта спецификация должна быть связана с clone_spec для экземпляра примитивом операции. На некоторых платформах в качестве clone_spec может просто использоваться egress_spec.

14.1.3 Отражение

Отражение или мониторинга порта является стандартной сетевой функцией (см. например, http://en.wikipedia.org/wiki/Port_mirroring). В этом параграфе описан подход к реализации этой функции в P4. Мониторинг включает несколько этапов:

  • идентификация пакетов для «отражения»;

  • создание копий обнаруженных пакетов;

  • задание действий, выполняемых с созданными копиями.

Обычно эти функции логически группируются в сеанс «отражения» (mirror session). В предположении минимальной поддержки со стороны платформы (например, предоставление внутренних метаданных) программа P4 может включать для поддержки входного мониторинга пакетов такие параметры как входной порт, VLAN ID, адрес L3 и протокол IP.

В приведенном примере предполагается, что блок буферизации обеспечивает программируемое сопоставление (отображение) параметра clone_spec, передаваемого примитиву clone_i2e, на номер выходного порта (egress_port). Сначала объявляется таблица для сопоставления по указанным параметрам, которая будет указывать действия вида

action mirror_select(session) { // Выбор пакетов и сопоставление с сессией
	modify_field(local_metadata.mirror_session, session);
	clone_i2e(session, mirror_fld_list);
}

где

field_list mirror_field_list {
	local_metadata.mirror_session;
}

указывает, что в клонированных пакетах должна указываться сессия отражения. Это действие создает новую копию входного пакета для представления в выходной конвейер. Интерфейс run-time API позволяет точно указать отображаемые (клонируемые) пакеты. Он также позволяет гибко выбирать идентификаторы сессий отражения для каждого такого пакета. Таблица mirror_select будет включена в поток управления для входного конвейера (возможно в начале обработки).

В выходной конвейер будет включена таблица local_metadata.mirror_session. Предположим, что значение 0 указывает отсутствие «отражения», поэтому таблица будет применяться для всех пакетов, но действия по отражению будут применены лишь к тем пакетам, которые помечены для мониторинга. Например,

action mirror_execute(trunc_length) {
	truncate(trunc_length);
}

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

Для отображения на выходе применяется похожий подход, основанный на примитиве clone_e2e.

14.2 Рециркуляция и повторное представление


Рисунок 5. Рециркуляция и повторное представление.

На рисунке 5 показаны пути пакетов, повторно представляемых для обработки анализатору. Сверху показан путь пакетов повторного представления (resubmit), отправляемых действием входного конвейера. По завершении входного конвейера повторно представленный исходный пакет снова попадает в синтаксический анализатор вместе с метаданными, заданными действием. Анализатор может использовать эти метаданные для принятия при анализе решения, отличающегося от принятого в первом проходе.

Нижний путь показывает рециркуляцию пакета. После завершения входной и выходной обработки пакет собирается (возможно с использованием метаданных исходного пакета) и передается анализатору.

Операции resubmit и recirculate различаются по полю instance_type.

15 Приложения

15.1 Ошибки

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

  • Синтаксис ссылок не счетчики не согласован со ссылками на измерители. В измерителях используются скобки, а в счетчиках — отдельный параметр.
  • Механизм ссылок на вывод измерителей задан чересчур жестко. Выход измерителя (поле метаданных с «цветом» от измерителя) разрешено указывать как при объявлении, так и при вызове измерителя.

15.2 Соглашения о программировании (не завершено)

Ниже приведены соглашения, предложенные для программ P4.

  • Синтаксический анализ начинается с состояния анализатора start.
  • Поток управления начинается со входной функции управления.

15.3 История выпусков

Таблица 7. История выпусков.

Выпуск

Дата

Изменения

1.0.0-rc1

08.09.2014

Первая открытая версия.

1.0.0-rc2

09.09.2014

Исправлены незначительные опечатки.

1.0.0-rc3

30.12.2014

Включены некоторые пропущенные символы обращения (отрицания, ~). Отбрасывание в анализаторе обозначено parser_drop. Добавлен примитив действия add. Добавлен раздел, указывающий ошибки.

1.0.1

28.01.2015

Добавлены селекторы профилей действий и действий, а также атрибут таблиц support_timeout.

1.0.2

03.03.2015

Добавлены примитивы действий push и pop.

1.0.3

03.11.2016

15.3.3 Изменения в версии 1.0.3

1.0.4

24.05.2017

15.3.2 Изменения в версии 1.0.4

1.0.5

31.05.2018

15.3.1 Изменения в версии 1.0.5

15.3.1 Изменения в версии 1.0.5

  • 2.2.2 Стек заголовков

    • Изменена семантика стека заголовков для совместимости со спецификацией P416 и известными реализациями.

15.3.2 Изменения в версии 1.0.4

  • 9.1 Примитивы действий

    • Изменена семантика примитивов действий, чтобы обращение к недействительному заголовку давало неопределенный результат и непригодные заголовки пропускались в расчетах по списку полей.

  • 9.2.1 Семантика последовательных и параллельных операций

    • Семантика параллельных операций заменена на последовательную для соответствия имеющимся реализациям (например, bmv2).

  • Проверка пригодности (2.2.1 Проверка пригодности экземпляров заголовков и метаданных)

    • Семантика изменена так, что поля непригодных заголовков становятся недействительными в операциях сопоставления с таблицами.

  • 11 Объявления таблиц

    • Добавлено псевдополе hdr.valid, которое можно сопоставлять с любой таблицей.

15.3.3 Изменения в версии 1.0.3

  • Счетчики и измерители (7.1 Счетчики и 7.2 Измерители)

    • Добавлен тип счетчиков packets_and_bytes.

    • Приведен пример цветового кодирования для измерителя.

    • Устранена неоднозначность при анализе путем замены meter() на execute_meter() (9.1 Примитивы действий).

  • Схема регистров и методология доступа (7.3 Регистры и 9.1 Примитивы действий)

    • Отменена схема регистров.

    • Добавлены примитивы register_read и register_write вместо метода доступа на основе скобок.

  • Объявление зависимых от платформы примитивов действий (9.1 Примитивы действий)

    • Дополнительные примитивы действий нельзя объявлять в коде P4. Отсутствие строгой типизации и указателей направления (in, out) делало такую возможность практически бесполезной.

  • Новые примитивы действий (9.1 Примитивы действий)

    • Арифметические операторы subtract() и subtract_from_field().

    • Побитовые логические операторы bit_and(), bit_or() и bit_xor().

    • Операторы побитового сдвига shift_left() и shift_right().

    • Генератор случайных чисел modify_field_rng_uniform().

  • Прочие изменения

    • Примитив modify_field_with_hash_based_offset() взамен set_field_to_hash_index (9.1 Примитивы действий).

    • Все параметры примитивов действий push, pop, resubmit, recirculate, clone_* стали обязательными.

    • Параметр field_list примитивов clone_* может задавать лишь поля метаданных, а не заголовков.

    • Разрешено пустое тело функции при объявлении действия (9.2 Определение действий).

    • Указан список внутренних метаданных, поддерживаемых прототипом BMv2 [3], в разделе 6 Стандартные внутренние метаданные.

15.4 Терминология (не завершено)

Таблица 8. Определения терминов.

Термин

Перевод

Определение

Control Flow

Поток управления

Логика выбора применяемых таблиц в конвейере, служащая для определения порядка.

Egress Queuing

Выходные очереди

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

Egress Specification

Спецификация выхода

Метаданные, устанавливаемые входным конвейером для указания набора выходных портов (и числа экземпляров для каждого порта), куда передается пакет.

Order Dependency

Зависимость порядка

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

Parsed Representation

Разобранное представление

Представление заголовков пакета в форме набора экземпляров, каждый из которых состоит из полей.

Parser

Синтаксический анализатор

Функциональный блок, отображающий пакет на Parsed Representation.

Pipeline

Конвейер

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

15.5 P4 BNF

p4_program ::= p4_declaration +

p4_declaration ::=
	header_type_declaration |
	instance_declaration |
	field_list_declaration |
	field_list_calculation_declarationcalculated_field_declaration |
	value_set_declaration |
	parser_function_declaration |
	parser_exception_declaration |
	counter_declaration |
	meter_declaration |
	register_declaration |
	action_function_declaration |
	action_profile_declaration |
	action_selector_declaration |
	table_declaration |
	control_function_declaration

const_value ::= [ "+" | - ] [ width_spec ] unsigned_value
unsigned_value ::= binary_value | decimal_value | hexadecimal_value
binary_value ::= binary_base binary_digit+
decimal_value ::= decimal_digit+
hexadecimal_value ::= hexadecimal_base hexadecimal_digit+

binary_base ::= 0b | 0B
hexadecimal_base ::= 0x | 0X

binary_digit ::= _ | 0 | 1
decimal_digit ::= binary_digit | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
hexadecimal_digit ::=
	decimal_digit | a | A | b | B | c | C | d | D | e | E | f | F
width_spec ::= decimal_digit+ ’
field_value ::= const_value
header_type_declaration ::=
	header_type header_type_name { header_dec_body }

header_dec_body ::=
	fields { field_dec + }
	[ length : length_exp ; ]
	[ max_length : const_value ; ]

field_dec ::= field_name : bit_width [ ( field_mod ) ];
field_mod ::= signed | saturating | field_mod , field_mod
length_bin_op ::= "+" | - | "*" | "<<" | ">>"
length_exp ::=
	const_value |
	field_name |
	length_exp length_bin_op length_exp |
	( length_exp )
bit_width ::= const_value | "*"
instance_declaration ::= header_instance | metadata_instance
header_instance ::= scalar_instance | array_instance
scalar_instance ::= header header_type_name instance_name ;
array_instance ::=
	header header_type_name
		instance_name "[" const_value "]" ;

metadata_instance ::=
	metadata header_type_name
		instance_name [ metadata_initializer ] | ;

metadata_initializer ::= { [ field_name : field_value ; ] + }
header_ref ::= instance_name | instance_name "[" index "]"
index ::= const_value | last
field_ref ::= header_ref . field_name
field_list_declaration ::=
	field_list field_list_name {
		[ field_list_entry ; ] +
	}

field_list_entry ::=
	field_ref | header_ref | field_value | field_list_name | payload
field_list_calculation_declaration ::=
	field_list_calculation field_list_calculation_name {
		input {
			[ field_list_name ; ] +
		}
		algorithm : stream_function_algorithm_name ;
		output_width : const_value ;
	}
calculated_field_declaration ::=
	calculated_field field_ref { update_verify_spec + }

update_verify_spec ::=
	update_or_verify field_list_calculation_name [ if_cond ] ;

update_or_verify ::= update | verify
if_cond ::= if ( calc_bool_cond )
calc_bool_cond ::=
	valid ( header_ref | field_ref ) |
	field_ref == field_value
value_set_declaration ::= parser_value_set value_set_name;
parser_function_declaration ::=
	parser parser_state_name { parser_function_body }

parser_function_body ::=
	extract_or_set_statement*
	return_statement

extract_or_set_statement ::= extract_statement | set_statement
extract_statement ::= extract ( header_extract_ref );
header_extract_ref ::=
	instance_name |
	instance_name "[" header_extract_index "]"

header_extract_index ::= const_value | next

set_statement ::= set_metadata ( field_ref, metadata_expr ) ;
metadata_expr ::= field_value | field_or_data_ref

return_statement ::=
	return_value_type |
	return select ( select_exp ) { case_entry + }

return_value_type ::=
	return parser_state_name ; |
	return control_function_name ; |
	parse_error parser_exception_name ;

case_entry ::= value_list : case_return_value_type ;
value_list ::= value_or_masked [ , value_or_masked ]* | default

case_return_value_type ::=
	parser_state_name |
	control_function_name |
	parse_error parser_exception_name

value_or_masked ::=
	field_value | field_value mask field_value | value_set_name

select_exp ::= field_or_data_ref [, field_or_data_ref] *
field_or_data_ref ::=
	field_ref |
	latest.field_name |
	current( const_value , const_value )
parser_exception_declaration ::=
	parser_exception parser_exception_name {
		set_statement *
		return_or_drop ;
	}

return_or_drop ::= return_to_control | parser_drop
return_to_control ::= return control_function_name
counter_declaration ::=
	counter counter_name {
		type : counter_type ;
		[ direct_or_static ; ]
		[ instance_count : const_expr ; ]
		[ min_width : const_expr ; ]
		[ saturating ; ]
	}

counter_type ::= bytes | packets | packets_and_bytes
direct_or_static ::= direct_attribute | static_attribute
direct_attribute ::= direct : table_name
static_attribute ::= static : table_name
meter_declaration ::=
	meter meter_name {
		type : meter_type ;
		[ result : field_ref ; ]
		[ direct_or_static ; ]
		[ instance_count : const_expr ; ]
	}

meter_type ::= bytes | packets
register_declaration ::=
	register register_name {
		width_declaration ;
		[ direct_or_static ; ]
		[ instance_count : const_value ; ]
		[ attribute_list ; ]
	}

width_declaration ::= width : const_value ;

attribute_list ::= attributes : attr_entry
attr_entry ::= signed | saturating | attr_entry , attr_entry
action_function_declaration ::=
	action action_header { action_statement * }

action_header ::= action_name "(" [ param_list ] ")"
param_list ::= param_name [, param_name]*
action_statement ::= action_name "(" [ arg [, arg]* ] ")" ;
arg ::= param_name | field_value | field_ref | header_ref

action_profile_declaration ::=
	action_profile action_profile_name {
		action_specification
		[ size : const_value ; ]
		[ dynamic_action_selection : selector_name ; ]
	}

action_specification ::=
	actions { [ action_name ] + }

action_selector_declaration ::=
	action_selector selector_name {
		selection_key : field_list_calculation_name ;
	}

table_declaration ::=
	table table_name {
		[ reads { field_match + } ]
		table_actions
		[ min_size : const_value ; ]
		[ max_size : const_value ; ]
		[ size : const_value ; ]
		[ support_timeout : true | false ; ]
	}
field_match ::= field_or_masked_ref : field_match_type ;
field_or_masked_ref ::=
	header_ref | header_ref "." valid | field_ref | field_ref mask const_value

field_match_type ::= exact | ternary | lpm | range | valid

table_actions ::=
	action_specification | action_profile_specification

action_specification ::=
	actions { [ action_name ] + }

action_profile_specification ::=
	action_profile : action_profile_name

control_function_declaration ::=
	control control_fn_name control_block
control_block ::= { control_statement * }
control_statement ::=
	apply_table_call |
	apply_and_select_block |
	if_else_statement |
	control_fn_name ( ) ;

apply_table_call ::= apply ( table_name ) ;

apply_and_select_block ::= apply ( table_name ) { [ case_list ] }
case_list ::= action_case + | hit_miss_case +
action_case ::= action_or_default control_block
action_or_default ::= action_name | default
hit_miss_case ::= hit_or_miss control_block
hit_or_miss ::= hit | miss

if_else_statement ::=
	if ( bool_expr ) control_block
	[ else_block ]

else_block ::= else control_block | else if_else_statement
bool_expr ::=
	valid ( header_ref ) | bool_expr bool_op bool_expr |
	not bool_expr | ( bool_expr ) | exp rel_op exp | true | false

exp ::=
	exp bin_op exp | un_op exp | field_ref |
	value | ( exp )

bin_op ::= "+" | "*" | - | "<<" | ">>" | \& | "|" | ^
un_op ::= ~ | -
bool_op ::= or | and
rel_op ::= > | >= | == | <= | < | !=

15.6 Зарезервированные слова P4

Ниже приведен список зарезервированных слов P4, которые не следует применять в идентификаторах7.

apply
current
default
else
hit
if
last
latest
parse_error
payload
select
switch

15.7 Преобразование значений полей

Как отмечено в параграфе 1.5.1 Спецификации значений, может потребоваться преобразование значений, используемых в выражениях или назначенных экземпляру поля. Преобразование зависит от размера и наличия знака в исходном и целевом значении, а также насыщаемости целевого значения. Значение считается имеющим знак, если (1) оно имеет в начале явный символ — (минус) или является экземпляром поля, объявленным с атрибутом signed.

Правила преобразования приведены ниже.

  • Если размеры источника и цели совпадают, используется двоичное представление источника, но интерпретация может измениться в зависимости от наличия знака:
    • 7-битовое значение без знака 127 при преобразовании в 7-битовое значение со знаком даст -1.
  • Если размер источника меньше, значение расширяется с учетом наличия знака:

    • источник 7’b1111111 со знаком преобразуется 8-битовое значение 8’b11111111;
    • источник 4’b1100 без знака преобразуется в 8-битовое значение 8’b00001100.

  • Если размер источника больше, результат зависит от насыщаемости получателя. Эффект должен быть таким же, как при сложении источника с нулем:

    • источник с отрицательным знаком при преобразовании в насыщаемый получатель получит значение 0;
    • источник без знака со значением 17 при преобразовании в 4-битовое значение без знака с насыщением даст в результате 15, поскольку это значение получателя при насыщении;
    • источник без знака со значением 17 при преобразовании в 4-битовое значение без знака и насыщения даст в результате 1, поскольку произойдет переход в 0 при значении 15 (эквивалентно отсечке источника).

Для выражений определяется значение с большим размером и остальные значения приводятся к этому размеру с учетом наличия у них знака. Затем выражение вычисляется и результат преобразуется в соответствии с назначением.

15.8 Примеры

15.8.1 Аннотированный пример mTag

В этом параграфе представлен пример mTag, включающий две разных программы P4 — mtag-edge и mtag-aggregation, как указано в параграфе 1.2 Пример mTag. Код программ написан на языке P4, что позволяет использовать препроцессор C для файлов P4. В результате директивы #define и #include в программе дают такой же эффект, как в коде на языке C. Это удобно в примера, но язык P4 не требует применения такого синтаксиса.

Код примера разделен на несколько файлов, перечисленных ниже.

  • headers.p4 содержит объявления всех типов заголовков, используемых обеими программами;
  • parser.p4 содержит код анализатора, используемого обеими программами;
  • actions.p4 описывает действия, используемые обеими программами;
  • mtag-edge.p4 содержит программу для краевого коммутатора;
  • mtag-aggregation.p4 содержит программу для коммутатора агрегирования;

Полностью программный код представлен на сайте P4 [2].

Рассмотрим сначала файл header.p4.

////////////////////////////////////////////////////////////////
// Определения типов заголовков
////////////////////////////////////////////////////////////////
// Стандартный заголовок L2 Ethernet
header_type ethernet_t {
	fields {
		dst_addr	: 48; // размер поля в битах
		src_addr	: 48;
		ethertype	: 16;
	}
}

// Стандартный тег VLAN
header_type vlan_t {
	fields {
		pcp		:3;
		cfi		:1;
		vid		:12;
		ethertype	:16;
	}
}

// Специальный тег mTag управления пересылкой на уровне агрегирования в ЦОД
header_type mTag_t {
	fields {
		up1		: 8; // От краевого коммутатора в агрегирующий
		up2		: 8; // От нижестоящего к вышестоящему коммутатору
		down1		: 8; // От вышестоящего к нижестоящему коммутатору
		down2		: 8; // От агрегирующего коммутатора к краевому
		ethertype	: 16;// Ethertype в инкапсулированном пакете
	}
}
// Стандартный заголовок IPv4
header_type ipv4_t {
	fields {
		version		: 4;
		ihl		: 4;
		diffserv	: 8;
		totalLen	: 16;
		identification	: 16;
		flags		: 3;
		fragOffset	: 13;
		ttl		: 8;
		protocol	: 8;
		hdrChecksum	: 16;
		srcAddr		: 32;
		dstAddr		: 32;
		options		: *;	// Опции переменного размера
	}
	length : ihl * 4;
	max_length : 60;
}

// Предполагаются стандартные метаданные от компилятора.


// Далее определяются локальные метаданные.
//
// copy_to_cpu является примером зависящих от платформы
// внутренних метаданных. Это особое значение, приводящее
// к копированию пересылаемого пакета в управляющий CPU.

header_type local_metadata_t {
	fields {
		cpu_code	: 16; 	// Код для отправки пакета в CPU
		port_type	: 4;	// Тип порта: up, down, local...
		ingress_error	: 1;	// Ошибка при проверке входного порта
		was_mtagged	: 1;	// Отслеживание mTag на входе
		copy_to_cpu	: 1;	// особый код для копирования пакета в CPU
		bad_packet	: 1;	// Прочие ошибки
		color		: 8;	// Для измерителей
	}
}

Ниже приведен код анализатора, используемого обеими программами.

////////////////////////////////////////////////////////////////
// Функция анализатора и связанные с ней определения
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////

// Определения экземпляров заголовков
//
// Экземпляры заголовков обычно определяются в анализаторе, 
// поскольку здесь они инициализируются.
//
////////////////////////////////////////////////////////////////

header ethernet_t ethernet;
header vlan_t vlan;
header mTag_t mtag;
header ipv4_t ipv4;

// Объявление локального экземпляра метаданных.
metadata local_metadata_t local_metadata;

////////////////////////////////////////////////////////////////
// Описание состояний анализатора
////////////////////////////////////////////////////////////////

// анализ начинается с заголовка Ethernet.
parser start {
	return ethernet;
}

parser ethernet {
	extract(ethernet);	// Извлечение заголовка  Ethernet.
	return select(latest.ethertype) {
		0x8100:		vlan;
		0x800:		ipv4;
		default:	ingress;
	}
}

// Извлечение тега VLAN и проверка mTag
parser vlan {
	extract(vlan);
		return select(latest.ethertype) {
		0xaaaa:		mtag;
		0x800:		ipv4;
		default:	ingress;
	}
}

// mTag может размещаться только после тега VLAN 
parser mtag {
	extract(mtag);
	return select(latest.ethertype) {
		0x800:		ipv4;
		default:	ingress;
	}
}

parser ipv4 {
	extract(ipv4);
	return ingress;	// Анализ завершен, начинается сопоставление
}

В следующем файле определены применяемые программами действия.

////////////////////////////////////////////////////////////////
//
// actions.p4
//
// Этот файл определяет общие действия, которые могут применяться
// краевым или агрегирующим коммутатором.
//
////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////
// Действия, используемые в таблицах
////////////////////////////////////////////////////////////////

// Копирование пакета в CPU;
action common_copy_pkt_to_cpu(cpu_code, bad_packet) {
	modify_field(local_metadata.copy_to_cpu, 1);
	modify_field(local_metadata.cpu_code, cpu_code);
	modify_field(local_metadata.bad_packet, bad_packet);
}

// Отбрасывание пакета; возможна отправка в CPU и маркировка (плохой)
action common_drop_pkt(do_copy, cpu_code, bad_packet) {
	modify_field(local_metadata.copy_to_cpu, do_copy);
	modify_field(local_metadata.cpu_code, cpu_code);
	modify_field(local_metadata.bad_packet, bad_packet);
	drop();
}
// Указание типа порта. См. mtag_port_type.
// Разрешает индикацию ошибок.
action common_set_port_type(port_type, ingress_error) {
	modify_field(local_metadata.port_type, port_type);
	modify_field(local_metadata.ingress_error, ingress_error);
}

Далее приведен фрагмент программы mtag-edge.

////////////////////////////////////////////////////////////////
//
// mtag-edge.p4
//
// Файл задает поведение краевого коммутатора в примере mTag.
//
//
////////////////////////////////////////////////////////////////

// Включение определений заголовков и анализатора (с экземплярами)
#include "headers.p4"
#include "parser.p4"
#include "actions.p4"	// Для действий с префиксом common_

#define PORT_COUNT 64	// Число портов коммутатора

////////////////////////////////////////////////////////////////
// Определения таблиц
////////////////////////////////////////////////////////////////

// Удаление mtag для локальной обработки и коммутации.
action _strip_mtag() {
	// Вырезание тега из пакета.
	remove_header(mtag);
	// Сохранение информации о наличии тега.
	modify_field(local_metadata.was_mtagged, 1);
}
// Теги mtag всегда вырезаются на краевом коммутаторе
table strip_mtag {
	reads {
		mtag	: valid; // Тег mtag был найден?
	}
	actions {
		_strip_mtag;	// Вырезать mtag и записать метаданные.
		no_op;		// Пропустить без обработки.
	}
}

////////////////////////////////////////////////////////////////
// Идентификация входного порта: local, up1, up2, down1, down2
table identify_port {
	reads {
		standard_metadata.ingress_port : exact;
	}
	actions { // Каждая запись таблицы задает одно действие.
		common_set_port_type;
		common_drop_pkt;	// Неизвестный порт.
		no_op;			// Продолжение обработки пакета.
	}
	max_size : 64; // Одно правило на порт.
}
. . .	// Здесь задан код локальной коммутации

// Добавление mTag в пакет и выбор выходной спецификации по up1
action add_mTag(up1, up2, down1, down2) {
	add_header(mtag);	// Копирование VLAN ethertype в mTag
	modify_field(mtag.ethertype, vlan.ethertype);
	// Установка VLAN ethertype для сигнализации mTag
	modify_field(vlan.ethertype, 0xaaaa);
	// Добавление маршрутной информации источника тега
	modify_field(mtag.up1, up1);
	modify_field(mtag.up2, up2);
	modify_field(mtag.down1, down1);
	modify_field(mtag.down2, down2);
	// Установка выходного порта получателя по данным тега
	modify_field(standard_metadata.egress_spec, up1);
}
// Учет пакетов и байтов
counter pkts_by_dest {
	type : packets;
	direct : mTag_table;
}
counter bytes_by_dest {
	type : bytes;
	direct : mTag_table;
}
// Проверка и при необходимости добавление mtag.
table mTag_table {
	reads {
		ethernet.dst_addr	: exact;
		vlan.vid		: exact;
	}
	actions {
		add_mTag;	// Действие для установки mtag.
		// Возможна отправка в CPU, если mtag не устанавливается
		common_copy_pkt_to_cpu;
		no_op;
	}
max_size	: 20000;
}
// Пакеты от уровня агрегирования должны оставаться локальными 
table egress_check {
	reads {
		standard_metadata.ingress_port : exact;
		local_metadata.was_mtagged : exact;
	}
	actions {
		common_drop_pkt;
		no_op;
	}
	max_size : PORT_COUNT; // Не более 1 правила на порт
}

// Выходные измерения. Их можно выполнить напрямую, но здесь программе
// разрешено использовать отображение для привязки ячейки измерителя
// к паре отправитель-получатель
meter per_dest_by_source {
	type : bytes;
	result : local_metadata.color;
	instance_count : PORT_COUNT * PORT_COUNT;	// Для пары отпр.-получ.
}
action meter_pkt(meter_idx) {
	execute_meter(per_dest_by_source, meter_idx, local_metadata.color);
}

// Цветовая маркировка для восходящих (uplink) портов.
table egress_meter {
	reads {
		standard_metadata.ingress_port : exact;
		mtag.up1 : exact;
	}
	actions {
		meter_pkt;
		no_op;
	}
	size : PORT_COUNT * PORT_COUNT;	// Может быть меньше
}
// Применение правил измерителя
counter per_color_drops {
	type : packets;
	direct : meter_policy;
}

table meter_policy {
	reads {
		metadata.ingress_port : exact;
		local_metadata.color : exact;
	}
	actions {
		drop; //Автоматически учитывается приведенным выше прямым счетчиком
		no_op;
	}
	size : 4 * PORT_COUNT;
}

////////////////////////////////////////////////////////////////
// Определения функций управления
////////////////////////////////////////////////////////////////

// Входная функция управления
control ingress {
	// Всегда вырезать тег mtag, сохраняя состояние
	apply(strip_mtag);
	// Определение типа порта-источника
	apply(identify_port);
	// Продолжение, если нет ошибки source_check
	if (local_metadata.ingress_error == 0) {
		// Попытка коммутации конечному хосту
		apply(local_switching); // Сопоставление по адресу получателя (не показано)
		// Не локальная коммутация с попыткой установить mtag
		if (standard_metadata.egress_spec == 0) {
			apply(mTag_table);
		}
	}
}

// Выходная функция управления
control egress {
	// Проверка неизвестного состояния на выходе и непригодного mTag.
	apply(egress_check);
	// Применение таблицы egress_meter и измерение в случае совпадения
	apply(egress_meter) {
		hit {
			apply(meter_policy);
		}
	}
}

Ниже показана фрагмент программы mtag-aggregation.

////////////////////////////////////////////////////////////////
//
// mtag-aggregation.p4
//
////////////////////////////////////////////////////////////////

// Включение определений заголовков и анализатора (с экземплярами)
#include "headers.p4"
#include "parser.p4"
#include "actions.p4"	// Для действий с префиксом common_

////////////////////////////////////////////////////////////////
// Таблица check_mtag 
// Проверяется тег mtag и при отсутствии выполняется правило drop или to-cpu
////////////////////////////////////////////////////////////////
table check_mtag { // Статически запрограммировано с 1 записью 
	. . . // Проверка пригодности тега mtag; отбрасывание или копия в CPU
}

////////////////////////////////////////////////////////////////
// Таблица identify_port
// Проверка направления порта (up, down) заданного при работе.
////////////////////////////////////////////////////////////////

table identify_port {
	. . . // Считывание входного порта, вызов common_set_port_type.
}

////////////////////////////////////////////////////////////////

// Действия по копированию нужного поля из mtag в выходную спецификацию
action use_mtag_up1() { // Не применяется агрегирующим коммутатором
	modify_field(standard_metadata.egress_spec, mtag.up1);
}
action use_mtag_up2() {
	modify_field(standard_metadata.egress_spec, mtag.up2);
}
action use_mtag_down1() {
	modify_field(standard_metadata.egress_spec, mtag.down1);
}
action use_mtag_down2() {
	modify_field(standard_metadata.egress_spec, mtag.down2);
}

// Таблица для выбора выходной спецификации по mtag
table select_output_port {
	reads {
		local_metadata.port_type	: exact; // Up, down (1 или 2).
	}
	actions {
		use_mtag_up1;
		use_mtag_up2;
		use_mtag_down1;
		use_mtag_down2;
		// Если тип порта не опознан, применяется предыдущее правила
		no_op;
	}
	max_size : 4; // Нужна лишь 1 запись на тип порта.
}

////////////////////////////////////////////////////////////////
// Определения управляющих функций
////////////////////////////////////////////////////////////////

// Входная функция управления
control ingress {
	// Проверка соответствия mTag и порта
	apply(check_mtag);
	apply(identify_port);
	apply(select_output_port);
}
// В примере mtag-agg не используется выходная функция управления.

Ниже представлен пример заголовочного файла, который можно применить в рассмотренном выше примере mtag. Этот файл включает ряд перечисленных ниже элементов.

  • Определения типов для портов (mtag_port_type_t), уровня измерителей (mtag_meter_levels_t) и обработчиков в таблицах (entry_handle_t).
  • Пример функции для добавления записи в таблицу identify_port (table_identify_port_add_with_set_port_type). Действие для использования в записи указано в конце имени функции set_port_type.
  • Функции для установки принятого по умолчанию действия в таблице identify_port (table_indentify_port_default_common_drop_pkt и table_indentify_port_default_common_set_port_type).
  • Функция для добавления записи в таблицу mTag (table_mTag_table_add_with_add_mTag).
  • Функция для чтения счетчика, связанного с таблицей измерителя (counter_per_color_drops_get).

/**
* Пример заголовочного файла (run-time) для примера CCR mTag
*/

#ifndef MTAG_RUN_TIME_H
#define MTAG_RUN_TIME_H

/**
* @brief типы портов, требуемые для примера mtag
*
* Указывает типы портов для краевого и агрегирующего коммутатора.
*/
typedef enum mtag_port_type_e {
	MTAG_PORT_UNKNOWN,	/* Тип неинициализированного порта */
	MTAG_PORT_LOCAL,	/* Локальный порт краевого коммутатора*/
	MTAG_PORT_EDGE_TO_AG1,	/* Up1 - от краевого коммутатора на уровень агрегирования 11 */
	MTAG_PORT_AG1_TO_AG2,	/* Up2 - от уровня агрегирования 1 на уровень 2 */
	MTAG_PORT_AG2_TO_AG1,	/* Down2 - от уровня агрегирования 2 на уровень 1 */
	MTAG_PORT_AG1_TO_EDGE,	/* Down1 - от уровня агрегирования 1 в краевой коммутатор*/
	MTAG_PORT_ILLEGAL,	/* Недопустимое значение */
	MTAG_PORT_COUNT
} mtag_port_type_t;

/**
* @brief Цвета для измерителей
*
* Краевой коммутатор поддерживает измерение от локальных портов
* на уровень агрегирования.
*/
typedef enum mtag_meter_levels_e {
	MTAG_METER_COLOR_GREEN,	/* Нет перегрузки */
	MTAG_METER_COLOR_YELLOW, 	/* Выше нижнего уровня */
	MTAG_METER_COLOR_RED,		/* Выше верхнего уровня */
	MTAG_METER_COUNT
} mtag_meter_levels_t;

typedef uint32_t entry_handle_t;

/* таблица mTag */
/**
* @brief Добавление записи в таблицу идентификации портов на краю
* @param ingress_port - определенный номер порта
* @param port_type - тип, связанный с портом
* @param ingress_error - значение для индикации ошибки
*/
entry_handle_t table_identify_port_add_with_set_port_type(
	uint32_t ingress_port,
	mtag_port_type_t port_type,
	uint8_t ingress_error);

/**
* @brief Установка принятого по умолчанию действия таблицы
* идентификации портов для передачи пакета в CPU.
* @param do_copy - 1, если нужно отправить копию пакета в CPU
* @param cpu_code - при установленном указывает код причины
* @param bad_packet - 1 для пометки пакета как «плохого»
*
* Это позволяет программисту сказать: «Если порт не указан, 
* это ошибка и нужно посмотреть пакет».
*
* Можно также просто отбросить пакет.
*/

int table_indentify_port_default_common_drop_pkt(
	uint8_t do_copy,
	uint16_t cpu_code,
	uint8_t bad_packet);

/**
* @brief Установка принятого по умолчанию действия для
* таблицы идентификации портов.
* @param port_type - тип порта
* @param ingress_error - значение для индикации ошибки
*
* Это позволяет программисту сказать, что по умолчанию 
* порт считается локальным
*/
int table_indentify_port_default_common_set_port_type(
	mtag_port_type_t port_type,
	uint8_t ingress_error);

/**
* @brief Добавляет запись в таблицу mtag.
* @param dst_addr - адрес L2 MAC для сопоставления
* @param vid - тег VLAN для сопоставления
* @param up1 - значение up1 для использования в mTag
* @param up2 - значение up2 для использования в mTag
* @param down1 - значение down1 для использования в mTag
* @param down2 - значение down2 для использования в mTag
*/
entry_handle_t table_mTag_table_add_with_add_mTag(
	mac_addr_t dst_addr, uint16_t vid,
	uint8_t up1, uint8_t up2, uint8_t down1, uint8_t down2);

/**
* @brief Возвращает число фактов отбрасывания по входным порта и цвету
* @param ingress_port - входной порт для запроса значения
* @param color - цвет для запроса значения
* @param count (output) - текущее значение параметра.
* @returns - 0 при успешном считывании.
*/
int counter_per_color_drops_get(
	uint32_t ingress_port,
	mtag_meter_levels_t color,
	uint64_t *count);
#endif /* MTAG_RUN_TIME_H */

15.8.2 Гистерезис при измерениях mTag с регистрами

В предыдущем параграфе коммутатор mtag-edge использовал измеритель между локальным портом и уровнем агрегирования. Предположим, что моделирование сети показывает преимущество использования гистерезиса для измерителей. Т. е. когда измеритель находится в состоянии red, пакеты отбрасываются, пока тот не перейдет в состояние green (не yellow). Это можно реализовать путем добавления массива регистров в параллель с измерителями. Каждая ячейка массива будет хранить «предыдущий» цвет для измерителя. Для этого в программу нужно внести изменения. Индекс измерителя для удобства сохраняется в локальных метаданных.

////////////////////////////////////////////////////////////////
//
// headers.p4 - добавляет индекс измерителя в локальные метаданные.
//
////////////////////////////////////////////////////////////////
header_type local_metadata_t {
	fields {
		cpu_code	: 16; 	// Код для пакета, передаваемого в CPU
		port_type	: 4;	// Тип порта - up, down, local...
		ingress_error	: 1;	// Ошибка при проверке входного порта
		was_mtagged	: 1;	// Отслеживать пакеты с mtag на входе
		copy_to_cpu	: 1;	// Специальный код для отправки копии в CPU
		bad_packet	: 1;	// Прочие ошибки
		color		: 8;	// Для измерителя
		prev_color	: 8;	// Для гистерезиса измерителя
		meter_idx	: 16; 	// Индекс измерителя
	}
}

////////////////////////////////////////////////////////////////
// mtag-edge.p4 - объявление регистров и добавление таблицы для их обновления
////////////////////////////////////////////////////////////////

// Регистр сохраняет «предыдущее» состояние (цвет) измерителя.
// Индекс совпадает с индексом измерителя.
register prev_color {
	width : 8;	// Пара для указанного выше измерителя.
	instance_count : PORT_COUNT * PORT_COUNT;
}

// Обновление цвета, сохраненного в регистре
action update_prev_color(new_color) {
	register_write(prev_color, local_metadata.meter_idx, new_color);
}

// Изменение цвета в соответствии с параметром
action mark_pkt(color) {
	modify_field(local_metadata.color, color);
}

// Обновление измерителя пакетов для сохранения данных
action meter_pkt(meter_idx) {
	// Сохранение индекса и предшествующего цвета в метаданных пакета
	modify_field(local_metadata.meter_idx, meter_idx);
	register_read(local_metadata.prev_color, prev_color, meter_idx);
	execute_meter(per_dest_by_source, meter_idx, local_metadata.color);
}

//
// Эта таблица статически заполняется по приведенным ниже правилам
// color: green,	prev_color: red	==> update_prev_color(green)
// color: red,		prev_color: green	==> update_prev_color(red)
// color: yellow, 	prev_color: red	==> mark_pkt(red)
// Иначе no-op.
//
table hysteresis_check {
	reads {
		local_metadata.color : exact;
		local_metadata.prev_color : exact;
	}
	actions {
		update_prev_color;
		mark_pkt;
		no_op;
	}
	size : 4;
}
////////////////////////////////////////////////////////////////
// Проверка гистерезиса в выходной функции управления.
////////////////////////////////////////////////////////////////
control egress {
	// Проверка неизвестного состояния выхода или непригодного mTag.
	apply(egress_check);
	apply(egress_meter) {
		hit {
			apply(hysteresis_check);
			apply(meter_policy);
		}
	}
}

15.8.3 Пример выбора ECMP

Этот пример показывает возможную реализацию выбора среди равноценных путей (ECMP) с помощью профиля действий с селектором действия.

table ipv4_routing {
	reads {
		ipv4.dstAddr: lpm;
	}
	action_profile : ecmp_action_profile;
	size : 16384;	// 16K возможных префиксов IPv4
}
action_profile ecmp_action_profile {
	actions {
		nhop_set;
		no_op;
	}
	size : 4096;	// 4K возможных next hop
	dynamic_action_selection : ecmp_selector;
}
// Список полей, применяемых для определения ECMP next hop
field_list l3_hash_fields {
	ipv4.srcAddr;
	ipv4.dstAddr;
	ipv4.protocol;
	tcp.sport;
	tcp.dport;
}
field_list_calculation ecmp_hash {
	input {
		l3_hash_fields;
	}
	algorithm : crc16;
	output_width : 16;
}
action_selector ecmp_selector {
	selection_key : ecmp_hash;
}

15.9 Свойства, предлагаемые для будущих версий

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

Таблица 9. Предложения на будущее.

Название

Суть предложения

Поддержка операторов присваивания

Возможность манипулировать полями и заголовками с помощью операторов присваивания, таких как = или +=.

Поддержка типизации

Поддержка типов для данных и объектов.

Улучшенная поддержка инкапсуляции

Поддержка более эффективных примитивов действий и функций анализатора для инкапсуляции.

Изменение конфигурации при работе

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

Псевдонимы полей и заголовков

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

Гибкое включение функций

Добавить возможность выбора при компиляции или в процессе работы тех или иных свойств в соответствии с их доступностью.

Средства отладки

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

Непрямое сопоставление с таблицами

Поддержка похожих на базы данных таблиц с возможностью нескольких запросов для одного СД.

Циклы в анализаторе

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

Select+Extract в анализаторе

Расширение оператора select для совместного использования с оператором extract, позволяющего выбрать экземпляр заголовка для извлечения.

15.10 Литература

[1] Bosshart, et al. P4: Programming Protocol-Independent Packet Processors8. Computer Communication Review, July 2014. http://www.sigcomm.org/ccr/papers/2014/July/0000000.0000004.

[2] The P4 Language Consortium web site. http://www.p4.org.

[3] The BMv2 Simple Switch target. https://github.com/p4lang/behavioral-model/blob/master/docs/simple_switch.md.

Николай Малых

nmalykh@protokols.ru

1

2В оригинале ошибочно указано отсутствующее Приложение 17.5. Прим. перев.

3В оригинале ошибочно указан раздел 5. Прим. перев.

4Перевод документа доступен по ссылке. Прим. перев.

5В оригинале ошибочно указан параграф 6.6.1. Прим. перев.

6В общем случае все аспекты рабочей (run-time) конфигурации относятся к плоскости управления и выходят за рамки данной спецификации P4. В будущем сообщество P4 может задать эти аспекты в отдельной спецификации.

7Вопрос фактического резервирования слов в P4 остается открытым.

8Перевод статьи на русский язык доступен по ссылке. Прим. перев.

Рубрика: SDN, Сетевое программирование | Комментарии к записи Спецификация языка P4_14, версия 1.0.5 отключены

bpf-helpers — функции-помощники Linux

bpf-helpers — функции-помощники Linux

По материалам Linux man

PDF

Подсистема расширенных фильтров Беркли (extended Berkeley Packet Filter или eBPF) состоит из программ на языке псевдоассемблера, котороые присоединяются к одной из нескольких ловушек в ядре (kernel hook) и работают при определённых событиях. Эта модель отличается об прежней «классической» модели фильтров («classic» BPF или cBPF) в нескольких аспектах, одним из которых является возможность вызывать из программы специальные функции-помощники (helper). Набор доступных функций определяется списком (white-list) вспомогательных функций в ядре.

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

По принятым в eBPF соглашениям вспомогательная функция не может принимать более 5 аргументов.

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

В этом документе приведён список вспомогательных функций, доступных разработчикам программ eBPF. Функции отсортированы в хронологическом порядке их добавления в ядро (начиная с наиболее старых).

bpf_map_lookup_elem

void *bpf_map_lookup_elem(struct bpf_map *map, const void *key)

Поиск записи в отображении map по заданному ключу key. Если запись не найдена, функция возвращает NULL.

bpf_map_update_elem

long bpf_map_update_elem(struct bpf_map *map, const void *key, const void *value, u64 flags)

Добавляет или обновляет запись в отображении map, заданном ключом key. Значения флагов указаны ниже.

BPF_NOEXIST

Записи для ключа key не должно присутствовать в отображении map.

BPF_EXIST

Запись для ключа key должна присутствовать в отображении map.

BPF_ANY

Условие наличия записи для key не задано.

Значение флага BPF_NOEXIST не может использоваться для отображений типа BPF_MAP_TYPE_ARRAY или BPF_MAP_TYPE_PERCPU_ARRAY (все элементы существуют всегда), иначе функция будет возвращать ошибку.

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_map_delete_elem

long bpf_map_delete_elem(struct bpf_map *map, const void *key)

Удаляет из отображения map запись с ключом key.

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_probe_read

long bpf_probe_read(void *dst, u32 size, const void *unsafe_ptr)

В программе трассировки (безопасно) пытается прочитать size байтов из памяти ядра по указателю unsafe_ptr и сохранить их в dst.

Обычно вместо этой функции применяется Generally, use bpf_probe_read() или bpf_probe_read_kernel().

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_ktime_get_ns

u64 bpf_ktime_get_ns(void)

Возвращает время, прошедшее с момента загрузки системы, в наносекундах. Время, в течение которого система была приостановлена (suspend), не учитывается, см. clock_gettime(CLOCK_MONOTONIC).

Функция возвращает текущее значение ktime.

bpf_trace_printk

long bpf_trace_printk(const char *fmt, u32 fmt_size, ...)

Это предназначенная для отладки функция в стиле printk(), выводящая сообщение в формате fmt (размером fmt_size) в файл /sys/kernel/debug/tracing/trace отладочной файловой системы DebugFS, если он доступен. Функция может принимать до 3 дополнительных аргументов u64 (в соответствии с общим ограничением eBPF в 5 аргументов).

При каждом вызове функции она добавляет строку в файл trace. Строки отбрасываются при открытии файла /sys/kernel/debug/tracing/trace. Чтобы предотвратить это используется /sys/kernel/debug/tracing/trace_pipe. Формат трассировки можно настраивать с помощью опций, заданных в файле /sys/kernel/debug/tracing/trace_options (см. файл README в каталоге /sys/kernel/debug/tracing). По умолчанию выводятся строки вида

telnet-470   [001] .N.. 419421.045894: 0x00000001: <formatted msg>

Здесь telnet указывает имя текущей задачи, 470 — её идентификатор (PID), 001 — номер процессора (CPU) на котором выполняется задача. В последовательности .N.. каждый символ относится к установке опций (включение прерываний, планирование, работа аппаратных и программных прерываний, уровень preempt_disabled). N в данном случае говорит об установке TIF_NEED_RESCHED и PREEMPT_NEED_RESCHED. Значение 419421.045894 указывает метку времени, 0x00000001 — фиктивное значение, используемое BPF для регистра указателя инструкций. <formatted msg> содержит сообщение в формате fmt.

Спецификаторы преобразования для fmt похожи на применяемые в printk(), но включают лишь %d, %i, %u, %x, %ld, %li, %lu, %lx, %lld, %lli, %llu, %llx, %p, %s. Модификаторы вывода (размер поля, заполнение нулями и т. п.) не поддерживаются, а при наличии непонятного спецификатора функция возвращает лишь -EINVAL (ничего не печатая).

Функция bpf_trace_printk() достаточно медленная и применять её следует лишь при отладке. Поэтому в журналах ядра выводится блок уведомления (для нескольких строк), указывающий, что эту функцию не следует применять в рабочих системах (production use), при её первом использовании (точнее, при выделении буферов trace_printk()). Для передачи значений в пользовательское пространство следует отдавать предпочтение событиям perf.

Функция возвращает число записанных в буфер байтов, а при отказе — отрицательное значение.

bpf_get_prandom_u32

u32 bpf_get_prandom_u32(void)

Возвращает псевдослучайное значение. С точки зрения безопасности эта функция использует своё псевдослучайное внутреннее состояние и не может служить для получения затравки (seed) других псевдослучайных функций в ядре. Важно понимать, что используемый функцией генератор на является криптографически защищенным.

Функция возвращает случайное 32-битовое число без знака.

bpf_get_smp_processor_id

u32 bpf_get_smp_processor_id(void)

Определяет идентификатор процессора SMP (symmetric multiprocessing). Отметим, что все программы работают с выключенным вытеснением (preemption), поэтому идентификатор процессора SMP не меняется в процессе выполнения программы.

Функция возвращает SMP id для процессора, на котором выполняется программа.

bpf_skb_store_bytes

long bpf_skb_store_bytes(struct sk_buff *skb, u32 offset, const void *from, u32 len, u64 flags)

Сохраняет len байтов, указанных адресом from, в пакете, связанном с skb, по указанному смещению offset. Параметр flags указывает комбинацию BPF_F_RECOMPUTE_CSUM (автоматический пересчет контрольной суммы пакета после записи байтов) и BPF_F_INVALIDATE_HASH (установка для skb->hash, skb->swhash и skb->l4hash значений 0).

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

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_l3_csum_replace

long bpf_l3_csum_replace(struct sk_buff *skb, u32 offset, u64 from, u64 to, u64 size)

Пересчитывает контрольную сумму сетевого уровня L3 (например, IP) для пакета, связанного с skb. Расчёт выполняется инкрементно, поэтому функция должна знать размер (size, 2 или 4) и прежнее значение изменяемого поля (from) заголовка, заменяемого новым значением (to). Возможно сохранение разности между прежним и новым значением в поле to путём установки from=0 и size=0. В обоих случаях параметр offset указывает местоположение поля IP checksum в пакете.

Эта функция работает в сочетании с bpf_csum_diff(), которая не обновляет контрольную сумму на месте, обеспечивает большую гибкость и может работать с полями контрольной суммы другого размера (не только 2 и 4).

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

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_l4_csum_replace

long bpf_l4_csum_replace(struct sk_buff *skb, u32 offset, u64 from, u64 to, u64 flags)

Пересчитывает контрольную сумму транспортного уровня L4 (например, TCP, UDP, ICMP) для пакета, связанного с skb. Расчёт выполняется инкрементно, поэтому функция должна знать размер (4 младших бита поля flags) и прежнее значение изменяемого поля (from) заголовка, заменяемого новым значением (to). Возможно сохранение разности между прежним и новым значением в поле to путём установки from=0 и и сброса (0) 4 младших битов поля flags. В обоих случаях параметр offset указывает местоположение поля контрольной суммы в пакете. В дополнение к размеру поле flags может содержать фактические флаги (побитовая операция OR). При установке BPF_F_MARK_MANGLED_0 нулевая контрольная сумма не пересчитывается (если нет также флага BPF_F_MARK_ENFORCE), а для обновлений, приводящих к нулевой контрольной сумме взамен устанавливается значение CSUM_MANGLED_0. Флаг BPF_F_PSEUDO_HDR указывает, что контрольная сумма рассчитывается заново для псевдозаголовка.

Эта функция работает в сочетании с bpf_csum_diff(), которая не обновляет контрольную сумму на месте, обеспечивает большую гибкость и может работать с полями контрольной суммы другого размера (не только 2 и 4).

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

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_tail_call

long bpf_tail_call(void *ctx, struct bpf_map *prog_array_map, u32 index)

Эта специальная функция служит для перехода в другую программу eBPF. Используется тот же кадр стека (значения стека и регистров для вызывающей программы недоступны вызываемой). Этот механизм позволяет создавать цепочки программ для увеличения максимального числа доступных инструкция eBPF или выполнения заданных программ по условию. Из соображений безопасности число последовательных вызовов (длина цепочки) ограничивается.

При вызове этой функции программа пытается перейти в программу, указанную параметром index в специальном отображении prog_array_map типа BPF_MAP_TYPE_PROG_ARRAY и передаёт указатель контекста ctx.

При успешном вызове ядро сразу же выполняет первую инструкцию вызванной программы. Это не вызов функции и управление в предыдущую (вызвавшую) программу не возвращается. Отказ при вызове не влияет на вызывающую программу и она просто продолжает работу. Причиной отказа может быть отсутствие вызываемой программы (т. е. значение index больше числа элементов в prog_array_map) или достигнута максимальная длина цепочки программ, задаваемая в ядре макросом MAX_TAIL_CALL_CNT (недоступен из пользовательского пространства). В настоящее время используется значение 32.

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_clone_redirect

long bpf_clone_redirect(struct sk_buff *skb, u32 ifindex, u64 flags)

Клонирует и перенаправляет пакет, связанный с skb, в другое сетевое устройство с индексом ifindex. Для перенаправления можно использовать входные и выходные интерфейсы в зависимости от наличия флага BPF_F_INGRESS в параметре flags (установка флага задает входной интерфейс, сброс — выходной). Иные флаги функция в настоящее время не поддерживает.

По сравнению с функцией bpf_redirect() использование bpf_clone_redirect() вызывает дополнительные издержки на дублирование буфера пакета, но это происходит вне программы eBPF. Функция bpf_redirect() более эффективна, но обрабатывается кодом действия и перенаправление происходит только после возврата из программы eBPF.

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

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_get_current_pid_tgid

u64 bpf_get_current_pid_tgid(void)

Возвращает 64-битовое целое число, содержащее текущие значения tgid и pid в форме

current_task->tgid << 32 | current_task->pid.

bpf_get_current_uid_gid

u64 bpf_get_current_uid_gid(void)

Возвращает 64-битовое целое число, содержащее текущие значения GID и UIDв форме

current_gid << 32 | current_uid.

bpf_get_current_comm

long bpf_get_current_comm(void *buf, u32 size_of_buf)

Копирует атрибут comm текущей задачи в buf размером size_of_buf. Атрибут comm содержит имя исполняемого файла (без пути) текущей задачи. Значение size_of_buf должно быть положительным. При успешном выполнении функции строка buf завршается NUL-символом, при отказе заполняется нулями.

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_get_cgroup_classid

u32 bpf_get_cgroup_classid(struct sk_buff *skb)

Извлекает значение classid для текущей задачи, т. е. для контрольной группы (cgroup) net_cls, к которой относится skb. Эту функцию можно применять на выходном пути TC1, но она непригодна для входного пути.

Группа управления net_cls обеспечивает интерфейс для маркировки сетевых пакетов на основе предоставленного пользователем идентификатора для всего трафика от задач, относящихся к соответствующей cgroup [1].

В ядре Linux имеется две версии cgroup — v1 и v2. Обе версии доступны для пользователей и могут применяться совместно, но следует отметить, что net_cls относится лишь к v1. Это делает функцию несовместимой с программами BPF, работающими только с v2 (сокет может включать в каждый момент данные лишь одной версии cgroup).

Эта функция доступна в ядре с опцией конфигурации CONFIG_CGROUP_NET_CLASSID, имеющей значение y или m.

Функция возвращает classid или значение 0 для принятого по умолчанию classid.

bpf_skb_vlan_push

long bpf_skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci)

Вталкивает vlan_tci (данные управления тега VLAN) протокола vlan_proto в пакет, связанный с skb, а затем обновляет контрольную сумму. Если vlan_proto отличается от ETH_P_8021Q и ETH_P_8021AD, предполагается ETH_P_8021Q.

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

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_skb_vlan_pop

long bpf_skb_vlan_pop(struct sk_buff *skb)

Выталкивает заголовок VLAN из пакета, связанного с skb.

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

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_skb_get_tunnel_key

long bpf_skb_get_tunnel_key(struct sk_buff *skb, struct bpf_tunnel_key *key, u32 size, u64 flags)

Возвращает метаданные туннеля, принимая указатель key на пустую структуру bpf_tunnel_key размером size, в которую помещаются метаданные туннеля для пакета, связанного с skb. В поле flags может помещаться флаг BPF_F_TUNINFO_IPV6, указывающий, что туннель использует протокол IPv6, а не IPv4.

Структура bpf_tunnel_key является объектом, обобщающим основные параметры, используемые разными туннельными протоколами. Её можно использовать для упрощения принятия решения на основе заголовка инкапсуляции. В частности, структура включает IP-адрес удалённой стороны (IPv4 или IPv6) в поле key->remote_ipv4 или key->remote_ipv6. Кроме того, структура раскрывает параметр key->tunnel_id, который обычно отображается на идентификатор виртуальной сети (Virtual Network Identifier или VNI), что позволяет программировать его с помощью функции bpf_skb_set_tunnel_key().

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

int ret;
struct bpf_tunnel_key key = {};

ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0);
if (ret < 0)
	return TC_ACT_SHOT;     // отбросить пакет

if (key.remote_ipv4 != 0x0a000001)
	return TC_ACT_SHOT;     // отбросить пакет

return TC_ACT_OK;               // воспринять пакет

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

Функция подходит для работы с такими туннелями, как VXLan, Geneve, GRE, IPIP.

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_skb_set_tunnel_key

long bpf_skb_set_tunnel_key(struct sk_buff *skb, struct bpf_tunnel_key *key, u32 size, u64 flags)

Заполняет структуру метаданных туннеля bpf_tunnel_key для пакета, связанного с skb. Структура указывается ключом key и имеет размер size. Поле flags может содержать комбинацию перечисленных ниже флагов.

BPF_F_TUNINFO_IPV6

Указывает, что туннель использует протокол IPv6, а не IPv4.

BPF_F_ZERO_CSUM_TX

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

BPF_F_DONT_FRAGMENT

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

BPF_F_SEQ_NUMBER

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

Ниже представлен пример использовани на выходном пути.

struct bpf_tunnel_key key;
	заполнение key ...
bpf_skb_set_tunnel_key(skb, &key, sizeof(key), 0);
bpf_clone_redirect(skb, vxlan_dev_ifindex, 0);

См. также описание функции bpf_skb_get_tunnel_key().

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_perf_event_read

u64 bpf_perf_event_read(struct bpf_map *map, u64 flags)

Считывает значение счётчика событий perf. Эта функция основана на отображении map типа BPF_MAP_TYPE_PERF_EVENT_ARRAY. Характер счётчика событий perf выбирается при обновлении map с помощью файловых дескрипторов событий perf. Отображение map является массивом, размер которого определяется числом доступных CPU, и каждый элемент содержит значение для одного процессора. Извлекаемое значение указывается параметром flags, который содержит индекс интересующего CPU с маской BPF_F_INDEX_MASK. В поле flags можно поместить значение BPF_F_CURRENT_CPU, указывающее извлечение счётчика для текущего CPU.

Отметим, что в Linux с ядрами до 4.13 доступны лишь аппаратные события perf.

В общем случае рекомендует использовать более новую функцию bpf_perf_event_read_value(), поскольку bpf_perf_event_read() имеет некоторые особенности ABI, когда в качестве кода возврата используется ошибка и значение счётчика (это некорректно, поскольку диапазоны могут перекрываться). Проблема решена в функции bpf_perf_event_read_value(), которая также предоставляет больше возможностей.

Функция возвращает значение счётчика событий perf из отображения или отрицательное значение в случае ошибки.

bpf_redirect

long bpf_redirect(u32 ifindex, u64 flags)

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

За исключением XDP2, для перенаправления могут использоваться входные и выходные интерфейсы в зависимости от наличия флага BPF_F_INGRESS в параметре flags (установленный флаг задаёт входной интерфейс, сброшенный — выходной). XDP в настоящее время поддерживает лишь перенаправление в выходной интерфейс и не принимает никаких флагов.

Такой же эффект можно получить с помощью функции bpf_redirect_map(), использующей отображение BPF для сохранения цели перенаправления вместо её прямого указания функции-помощнику.

Для XDP функция возвращает XDP_REDIRECT при успехе или XDP_ABORTED при ошибке. Для иных типов программ при успехе возвращается TC_ACT_REDIRECT, при ошибке — TC_ACT_SHOT.

bpf_get_route_realm

u32 bpf_get_route_realm(struct sk_buff *skb)

Извлекает область (realm) маршрута, т. е. поле tclassid для получателя в skb. Извлекаемый идентификатор является предоставленным пользователем тегом, подобным применяемому с net_cls cgroup (см. bpf_get_cgroup_classid()), но относящимся к маршруту (записи для адресата), а не к задаче.

Извлечение этого идентификатора работает с выходной ловушкой TC clsact (см. man 8 tc-bpf) или с классическими дисциплинами выходных очередей qdisc, не на входном пути TC. Вариант с выходной ловушкой TC clsact имеет преимущество в том, что запись для получателя ещё не отброшена на пути передачи, поэтому её не требуется удерживать искусственно через netif_keep_dst() как в классической дисциплине qdisc, пока skb не будет освобождён.

Эта функция доступна лишь с ядрами, собранными с опцией CONFIG_IP_ROUTE_CLASSID.

Функция возвращает область маршрута для пакета, связанного с skb, или 0, если ничего не найдено.

bpf_perf_event_output

long bpf_perf_event_output(void *ctx, struct bpf_map *map, u64 flags, void *data, u64 size)

Записывает блок необработанных данных (blob) в специальное событие BPF в отображении map типа BPF_MAP_TYPE_PERF_EVENT_ARRAY. Это событие должно иметь атрибуты PERF_SAMPLE_RAW sample_type, PERF_TYPE_SOFTWARE type и PERF_COUNT_SW_BPF_OUTPUT.

Аргумент flags служит для указания индекса в map, по которому должно размещаться значение, с применением маски BPF_F_INDEX_MASK. В качестве flags можно указать BPF_F_CURRENT_CPU для указания использования индекса текущего ядра CPU.

Записываемое значение размером size передаётся через стек eBPF и указывается параметром data.

Программе-помощнику должен также передаваться контекст ctx.

В пользовательском пространстве программе, желающей прочитать значения, нужно вызвать функцию perf_event_open() для события perf (на одном или всех CPU) и сохранить дескриптор файла в map. Это должно выполняться до того, как программа eBPF сможет передавать туда данные. Пример этого представлен в файле samples/bpf/trace_output_user.c дерева исходных кодов ядра Linux (программа eBPF находится в файле samples/bpf/trace_output_kern.c).

Функция bpf_perf_event_output() обеспечивает лучшую производительность, нежели bpf_trace_printk(), для совместного использования данных с пространством пользователей и гораздо лучше подходит для потоковых данных из программ eBPF.

Эта функция не ограничивается трассировкой и может применяться с программами, присоединёнными к TC или XDP, где она позволяет передавать данные получателям в пользовательском пространстве. Данными могут быть настраиваемые (custom) структуры и/или содержимое пакета (payload).

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_skb_load_bytes

long bpf_skb_load_bytes(const void *skb, u32 offset, void *to, u32 len)

Функция обеспечивает простой способ загрузки данных из пакета и может служить для загрузки len байтов, начиная со смещения offset, из пакета, связанного с skb, в буфер, указанный параметром to.

Начиная с ядра Linux 4.7 использование этой функции было в основном заменено прямым доступом к пакетам, позволяющим манипулировать данными пакета с skb->data и skb->data_end, указывающими первый байт и байт, следующий за последним. Однако функция остаётся полезной, если нужно однократно считать большой объем данных из пакета в стек eBPF.

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_get_stackid

long bpf_get_stackid(void *ctx, struct bpf_map *map, u64 flags)

Возвращает идентификатор стека пользовательского пространства или ядра. Для этого функции нужен указатель на контекст ctx, в котором выполняется программа трассировки, а также указатель на отображение map типа BPF_MAP_TYPE_STACK_TRACE. Аргумент flags указывает число пропускаемых кадров стека (0 — 255) с маской BPF_F_SKIP_FIELD_MASK. Может применяться комбинация указанных ниже флагов.

BPF_F_USER_STACK

Обращение к пользовательскому стеку, а не к стеку ядра.

BPF_F_FAST_STACK_CMP

Сравнение стеков только по хэш-значениям.

BPF_F_REUSE_STACKID

Если два хэш-значения дают одно значение stackid, более старый стек отбрасывается.

Получаемый идентификатор стека является целочисленным 32-битовым дескриптором, который можно комбинировать с другими данными (включая идентификаторы других стеков) и использовать в качестве ключей отображений. Это может быть полезно для создания различных графов (например, графы кадров или off-cpu).

Для обхода стека эта функция лучше, чем bpf_probe_read(), которую можно применять с развёрнутыми (unrolled) циклами, но она менее эффективна и использует много инструкций eBPF. Однако bpf_get_stackid() может собирать до PERF_MAX_STACK_DEPTH кадров ядра и пользовательских кадров. Отметим, что этот предел задаёт sysctl и его можно увеличить вручную для профилирования длинных пользовательских стеков (таких как стеки программ Java). Для этого служит команда вида

# sysctl kernel.perf_event_max_stack=<new value>

Функция возвращает положительный или нулевой (null) идентификатор стека при успешном выполнении и отрицательное значение в случае ошибки.

bpf_csum_diff

s64 bpf_csum_diff(__be32 *from, u32 from_size, __be32 *to, u32 to_size, __wsum seed)

Рассчитывает разность контрольных сумм необработанных (raw) буферов — указанного from, размером from_size и указанного to, размером to_size (размеры буферов должны быть кратны 4). К значению может добавляться необязательный параметр seed (это можно делать каскадно, принимая результат предыдущего вызова функции).

Функцию можно применять разными способами.

  • С from_size == 0, to_size > 0 и seed со значением контрольной суммы при добавлении данных.

  • С from_size > 0, to_size == 0 и seed со значением контрольной суммы при удалении данных из пакета.

  • С from_size > 0, to_size > 0 и seed = 0 для расчёта разности. Отметим, что размеры from_size и to_size могут различаться.

Эту функцию можно применять вместе с bpf_l3_csum_replace() и bpf_l4_csum_replace(), которым можно передать разность, определённую bpf_csum_diff().

Функция возвращает результат расчёта или отрицательный код ошибки при отказе.

bpf_skb_get_tunnel_opt

long bpf_skb_get_tunnel_opt(struct sk_buff *skb, void *opt, u32 size)

Извлекает метаданные опций туннеля для пакета, связанного с skb, и сохраняет необработанные данные в буфере opt размера size.

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

Функция возвращает размер найденный данных опций.

bpf_skb_set_tunnel_opt

long bpf_skb_set_tunnel_opt(struct sk_buff *skb, void *opt, u32 size)

Устанавливает метаданные опций туннеля для пакета, связанного с skb, на основе данных из необработанного буфера opt размером size. Дополнительные сведения приведены в описании функции bpf_skb_get_tunnel_opt().

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_skb_change_proto

long bpf_skb_change_proto(struct sk_buff *skb, __be16 proto, u64 flags)

Меняет для skb значение протокола на proto. В настоящее время можно заменить IPv4 на IPv6 и обратно. Функция выполняет подготовку к замене, включая изменение размера буфера сокета. Предполагается, что программа eBPF заполнит новые заголовки (при наличии) с помощью skb_store_bytes() и пересчитает контрольные суммы с помощью bpf_l3_csum_replace() и bpf_l4_csum_replace(). Основным назначением этой функции являются операции NAT64 из программы eBPF.

Тип GSO внутренне помечен как рискованный, поэтому заголовки проверяются, а сегменты пересчитываются машиной GSO/GRO. Размер для цели GSO адаптируется.

Значения параметра flags зарезервированы на будущее и поле должно иметь значение 0.

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

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_skb_change_type

long bpf_skb_change_type(struct sk_buff *skb, u32 type)

Меняет тип (адресата) для пакета, связанного с skb. Действие функции к установке для skb->pkt_type значения type. Программа eBPF не имеет другого доступа для записи в skb->pkt_type, кроме этой функции. Функция помогает изящно обрабатывать ошибки.

Основным применением является замена входящих skb на PACKET_HOST программным путём вместо рециркуляции через redirect(…, BPF_F_INGRESS), например.

Для type в настоящее время разрешены лишь указанные ниже значения.

PACKET_HOST

Пакет для нас (для данного хоста).

PACKET_BROADCAST

Передать пакет всем.

PACKET_MULTICAST

Передать пакет в группу.

PACKET_OTHERHOST

Передать пакето кому-либо иному.

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_skb_under_cgroup

long bpf_skb_under_cgroup(struct sk_buff *skb, struct bpf_map *map, u32 index)

Проверяет, является ли skb потомком группы управления cgroup2, содержащейся в отображении map типа BPF_MAP_TYPE_CGROUP_ARRAY по индексу index.

Возвращаемое значение определяется результатом проверки:

  • 0, если skb не является наследником cgroup2;

  • 1, если skb является наследником cgroup2;

  • отрицательное значение при возникновении ошибки.

bpf_get_hash_recalc

u32 bpf_get_hash_recalc(struct sk_buff *skb)

Извлекает хэш пакета skb->hash. Если значение не установлено, например, в результате изменения пакета (mangling), хэш рассчитывается заново. Последующий доступ к хэш-значению возможен напрямую через skb->hash.

Вызов bpf_set_hash_invalid(), смена прототипа пакета с помощью bpf_skb_change_proto() или вызов bpf_skb_store_bytes() с BPF_F_INVALIDATE_HASH могут приводить к очистке хэша и запуску нового расчёта для следующего вызова bpf_get_hash_recalc().

Функция возвращает 32-битовое хэш-значение.

bpf_get_current_task

u64 bpf_get_current_task(void)

Возвращает указатель на текущую структуру задачи (task).

bpf_probe_write_user

long bpf_probe_write_user(void *dst, const void *src, u32 len)

Пытается безопасным способом записать len байтов из буфера src в память dst. Функция работает только для потоков (thread) пользовательского контекста, а параметр dst должен указывать действительный в пользовательском пространстве адрес.

Эту функцию не следует применять для реализации каких-либо механизмов защиты из-за атак TOC-TOU, она предназначена, скорее, для отладки и управления исполнением полукооперативными процессами.

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

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_current_task_under_cgroup

long bpf_current_task_under_cgroup(struct bpf_map *map, u32 index)

Проверяет запущен ли тест (probe) в контексте данного подмножества иерархии cgroup2, содержащейся в отображении map типа BPF_MAP_TYPE_CGROUP_ARRAY по индексу index.

Возвращаемое значение определяется результатом проверки:

  • 0, если задача skb относится к cgroup2;

  • 1, если задача skb не относится к cgroup2;

  • отрицательное значение при возникновении ошибки.

bpf_skb_change_tail

long bpf_skb_change_tail(struct sk_buff *skb, u32 len, u64 flags)

Меняет (расширяет или сокращает) размер пакета, связанного с skb, на новое значение len. Поле flags является резервным и должно иметь значение 0.

Основная идея состоит в изменении функцией размера пакета, после чего программа eBPF переписывает остальное с помощью функций bpf_skb_store_bytes(), bpf_l3_csum_replace(), bpf_l4_csum_replace() и др. Эта функция служит утилитой медленного пути, предназначенной для откликов с управляющими сообщениями, поэтому сама является достаточно медленной, неявно линеаризуя, деклонируя и отбрасывая выгрузку из skb.

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

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_skb_pull_data

long bpf_skb_pull_data(struct sk_buff *skb, u32 len)

Извлекает нелинейные данные в случае, когда skb является нелинейным и не весь размер len относится к линейной части. Функция делает len буфера skb доступными для чтения и записи, при len=0 вытягивается skb целиком.

Эта функция нужна лишь для чтения или записи при прямом доступе к пакету.

При непосредственном доступе к пакету проверка того, что заданное для доступа смещение не выводит за границы пакета (проверка skb->data_end), может давать отрицательный результат, если смещение некорректно или запрошенные данные относятся к нелинейной части skb. В таком случае программа может выйти из строя или (в случае нелинейного буфера) использовать вспомогательную функцию для обеспечения доступности данных. Первым решением является вызов bpf_skb_load_bytes(), а другое заключается в использовании bpf_skb_pull_data для извлечения в один приём нелинейных частей с последующей проверкой и доступом к данным.

При этом гарантируется, что skb не будет клонироваться, что является необходимым условием для прямой записи. Поскольку инвариантность нужна лишь для записи, проверка обнаруживает запись и добавляет пролог, вызывающий bpf_skb_pull_data() для эффективного деклонирования skb в самом начале, если буфер действительно клонирован.

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

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_csum_update

s64 bpf_csum_update(struct sk_buff *skb, __wsum csum)

Добавляет csum к skb->csum, если драйвер ввёл в это поле контрольную сумму всего пакета. В противном случае возвращается ошибка. Эта функция предназначена для использования вместе с bpf_csum_diff(), в частности, для обновления контрольной суммы после записи данных в пакет при прямом доступе к нему.

Функция возвращает контрольную сумму при успешном выполнении и отрицательный код в случа ошибки.

bpf_set_hash_invalid

void bpf_set_hash_invalid(struct sk_buff *skb)

делает недействительным текущий хэш skb->hash. Это может использоваться после изменения (mangling) заголовков путём прямого доступа к пакету, чтобы указать несоответствие хэша и запустить его повторный расчёт при следующей попытке ядра получить доступ к этому хэш-значению или при вызове bpf_get_hash_recalc().

bpf_get_numa_node_id

long bpf_get_numa_node_id(void)

Возвращает идентификатор текущего узла NUMA4. Основным назначением функции является выбор сокетов для локального узла NUMA при подключении программы к сокетам с опцией SO_ATTACH_REUSEPORT_EBPF (см. man 7 socket), но она доступна и другим типам программ, подобно bpf_get_smp_processor_id().

bpf_skb_change_head

long bpf_skb_change_head(struct sk_buff *skb, u32 len, u64 flags)

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

Эту функцию можно использовать с L3 skb при вталкивания заголовка MAC для перенаправления на устройство L2.

Значения для флагов являются резервными и поле flags должно иметь значение 0.

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

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_xdp_adjust_head

long bpf_xdp_adjust_head(struct xdp_buff *xdp_md, int delta)

Перемещает данные xdp_md->data на delta байтов (значение delta может быть отрицательным). Функция может применяться для подготовки пакета к вталкиванию или выталкиванию заголовков.

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

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_probe_read_str

long bpf_probe_read_str(void *dst, u32 size, const void *unsafe_ptr)

Копирует строку с NUL-символом в конце из небезопасного адреса ядра unsafe_ptr в dst. Обычно вместо этой функции применяется bpf_probe_read_user_str() или bpf_probe_read_kernel_str().

При успешном копировании функция возвращает размер скопированной строки с учётом NUL-символа, а при ошибке — отрицательное значение.

bpf_get_socket_cookie

u64 bpf_get_socket_cookie(struct sk_buff *skb)

Если структура sk_buff, указанная skb, имеет известный сокет, функция извлекает (созданное ядром) значение cookie этого сокета. При отсутствии cookie создаётся новое значение, которое сохраняется в течение срока действия сокета. Функция может быть полезна для отслеживания статистики сетевого трафика на уровне сокета, поскольку она возвращает глобальный идентификатор сокета, который можно считать уникальным.

Функция возвращает 8-байтовое неубывающее значение при успехе или 0, если поля сокета нет в skb.

bpf_get_socket_cookie

u64 bpf_get_socket_cookie(struct bpf_sock_addr *ctx)

Эквивалентна функции bpf_get_socket_cookie(), получающей skb, но берет сокет из контекста структуры bpf_sock_addr.

Функция возвращает 8-байтовое неубывающее значение.

bpf_get_socket_cookie

u64 bpf_get_socket_cookie(struct bpf_sock_ops *ctx)

Эквивалентна функции bpf_get_socket_cookie(), получающей skb, но берет сокет из контекста структуры bpf_sock_ops.

Функция возвращает 8-байтовое неубывающее значение.

bpf_get_socket_uid

u32 bpf_get_socket_uid(struct sk_buff *skb)

Возвращает UID владельца сокета, связанного с skb. Для сокета NULL или неполного сокета (т. е. в состоянии time-wait или сокета запроса) возвращается значение overflowuid, которое может быть и фактическим значением UID для сокета.

bpf_set_hash

long bpf_set_hash(struct sk_buff *skb, u32 hash)

Устанавливает для полного хэша skb (поле skb->hash) значение hash.

Функция возвращает 0.

bpf_setsockopt

long bpf_setsockopt(void *bpf_socket, int level, int optname, void *optval, int optlen)

Эмулирует вызов setsockopt() на сокете, связанном с bpf_socket, который должен быть полным сокетом. Требуется указать уровень, где размещается опция и имя optname (см. man 2 setsockopt). Значение опции размером optlen указывает параметр optval.

Параметр bpf_socket имеет одно из указанных ниже значений.

  • структура bpf_sock_ops для BPF_PROG_TYPE_SOCK_OPS.

  • структура bpf_sock_ops для BPF_CGROUP_INET4_CONNECT и BPF_CGROUP_INET6_CONNECT.

Эта функция фактически реализует часть setsockopt() и поддерживает указанные ниже уровни.

SOL_SOCKET

Поддерживает значения optname: SO_RCVBUF, SO_SNDBUF, SO_MAX_PACING_RATE, SO_PRIORITY, SO_RCVLOWAT, SO_MARK, SO_BINDTODEVICE, SO_KEEPALIVE.

IPPROTO_TCP

Поддерживает значения optname: TCP_CONGESTION, TCP_BPF_IW, TCP_BPF_SNDCWND_CLAMP, TCP_SAVE_SYN, TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_KEEPCNT, TCP_SYNCNT, TCP_USER_TIMEOUT.

IPPROTO_IP

Поддерживает optname IP_TOS.

IPPROTO_IPV6

Поддерживает optname IPV6_TCLASS.

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_skb_adjust_room

long bpf_skb_adjust_room(struct sk_buff *skb, s32 len_diff, u32 mode, u64 flags)

Расширяет или сокращает пространство для данных в пакет, связанном с skb на len_diff байтов в соответствии с режимом mode.

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

BPF_F_ADJ_ROOM_NO_CSUM_RESET

Не сбрасывать выгруженные данные контрольной суммы skb в CHECKSUM_NONE.

В настоящее время поддерживается два режиме, указанных ниже.

BPF_ADJ_ROOM_MAC

Корректировка пространства на канальном уровне (размер пространства изменяется ниже заголовка L2).

BPF_ADJ_ROOM_NET

Корректировка пространства на сетевом уровне (размер пространства изменяется ниже заголовка L3).

Ниже перечислены поддерживаемые флаги.

BPF_F_ADJ_ROOM_FIXED_GSO

Не менять gso_size. Настройка mss в этом случае недоступна для дейтаграмм.

BPF_F_ADJ_ROOM_ENCAP_L3_IPV4 и BPF_F_ADJ_ROOM_ENCAP_L3_IPV6

Резервируется пространство для туннельного заголовка с корректировкой смещений skb и других полей.

BPF_F_ADJ_ROOM_ENCAP_L4_GRE и BPF_F_ADJ_ROOM_ENCAP_L4_UDP

Используются с флагом ENCAP_L3 для задания типа туннеля.

BPF_F_ADJ_ROOM_ENCAP_L2(len)

Используется с флагами ENCAP_L3/L4 для уточнения типа туннеля, len указывает размер внутреннего заголовка is MAC.

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

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_redirect_map

long bpf_redirect_map(struct bpf_map *map, u32 key, u64 flags)

Перенаправляет пакет конечной точке, указанной индексом key в отображении map. В зависимости от типа отображение map может указывать сетевые устройства (для пересылки пакета через другой порт) или CPU (для пересылки кадров XDP в другой CPU5).

Два младших бита параметра flags служат для возврата кода завершения в случае ошибки. Это сделано для того, чтобы можно было возвращать один из кодов завершения программы XDP (вплоть до XDP_TX), выбранный вызывающей стороной. Старшие биты параметра flags должны быть сброшены (0).

Похожая функция bpf_redirect() обеспечивает перенаправление по ifindex, не требуя для этого отображения.

Функция возвращает XDP_REDIRECT при успехе или код завершения программы в двух младших битах параметра flags в случае ошибки.

bpf_sk_redirect_map

long bpf_sk_redirect_map(struct sk_buff *skb, struct bpf_map *map, u32 key, u64 flags)

Перенаправляет пакет в сокет, указанный map (типа BPF_MAP_TYPE_SOCKMAP), по индексу key. Для перенаправления можно использовать входные и выходные интерфейсы, значение BPF_F_INGRESS в поле flags позволяет различать их (наличие флага указывает входной путь, отсутствие — выходной). Другие флаги не поддерживаются.

Функция возвращает SK_PASS при успехе, SK_DROP в случае ошибки.

bpf_sock_map_update

long bpf_sock_map_update(struct bpf_sock_ops *skops, struct bpf_map *map, void *key, u64 flags)

Добавляет запись в отображение map, указывающее сокет, или обновляет его. Параметр skops используется в качестве нового значения записи, связанной с key. Поле flags принимает одно из указанных ниже значений.

BPF_NOEXIST

Запись для key должна присутствовать в map.

BPF_EXIST

Запись для key уже имеется в map.

BPF_ANY

Условия по наличию записи для key не заданы.

Если map имеет программы eBPF (parser и verdict), они будут наследоваться добавляемым сокетом. Если сокет уже связан с программами eBPF, это приведёт к ошибке.

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_xdp_adjust_meta

long bpf_xdp_adjust_meta(struct xdp_buff *xdp_md, int delta)

Изменяет адрес, указанный xdp_md->data_meta на величину delta (может быть положительной и отрицательной). Отметим, что эта операция меняет адрес, хранящийся в xdp_md->data, поэтому он должен загружаться только после вызова функции.

Использование xdp_md->data_meta необязательно и от программ не требуется использовать его. Причина этого заключается в том, что при обработке пакета в XDP (например, фильтром DoS) возможно вталкивание дополнительных метаданных до передачи в стек с гарантией того, что входная программа eBPF, связанная с классификатором TC на том же устройстве, может получить их для последующей постобработки. Поскольку TC работает с буферами сокетов, остаётся возможность установки из XDP указателей метки или приоритета, а также других указателей для буфера сокетов. Универсальность и программируемость этого пространства данных обеспечивает большую гибкость, поскольку пользователь может сохранять любые нужные ему метаданные.

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

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_perf_event_read_value

long bpf_perf_event_read_value(struct bpf_map *map, u64 flags, struct bpf_perf_event_value *buf, u32 buf_size)

Считывает значение счётчика событий perf и сохраняет его в buf размером buf_size. Эта функция основана на отображении map типа BPF_MAP_TYPE_PERF_EVENT_ARRAY. Характер счётчика событий perf выбирается при обновлении map с помощью файловых дескрипторов событий perf. Отображение map является массивом, размер которого определяется числом доступных CPU, и каждый элемент содержит значение для одного процессора. Извлекаемое значение указывается параметром flags, который содержит индекс интересующего CPU с маской BPF_F_INDEX_MASK. В поле flags можно поместить значение BPF_F_CURRENT_CPU, указывающее извлечение счётчика для текущего CPU.

Эта функция себя подобно bpf_perf_event_read(), но вместо возврата наблюдаемого значения помещает его в структуру buf. Это позволяет извлечь дополнительные данные, в частности, копируется время включения (enable) и работы (running) в buf->enabled и buf->running. В общем случае рекомендуется применять bpf_perf_event_read_value(), а не bpf_perf_event_read(), у которой имеются проблемы с ABI и меньше возможностей.

Получаемые значения представляют интерес, поскольку аппаратные счётчики PMU6 имеют ограниченные ресурсы. Когда число открытых на основе PMU событий perf превышает число доступных счётчиков, ядро мультиплексирует эти события, чтобы каждому отдавалась некая доля времени PMU (но не всё). В случае мультиплексирования число выборок или значение счётчика не будут отражать ситуацию, которая была бы без мультиплексирования. Это осложняет сравнение разных запусков. Обычно значение счётчика следует нормализовать перед сравнением с другими экспериментами. Нормализация обычно имеет вид

normalized_counter = counter * t_enabled / t_running

где t_enabled — время, выделенное для события, а t_running — время, прошедшее для события с момента последней нормализации. Время включения и работы аккумулируется с момента события perf. Для масштабирования между двумя вызовами программы eBPF пользователи могут применять идентификатор CPU в качестве ключа (это типично для модели использования массива perf), чтобы запомнить прежнее значение и выполнить расчёт в программе eBPF.

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_perf_prog_read_value

long bpf_perf_prog_read_value(struct bpf_perf_event_data *ctx, struct bpf_perf_event_value *buf, u32 buf_size)

Для программы eBPF, присоединённой к событию perf, функция извлекает значение счётчика событий, связанных с ctx, и сохраняет его в структуре размера buf_size, указанной buf. Время включения и работы также сохраняются в структуре (см. bpf_perf_event_read_value().

Функция возвращает 0 при успешном выполнении и отрицательное значение при ошибке.

bpf_getsockopt

long bpf_getsockopt(void *bpf_socket, int level, int optname, void *optval, int optlen)

Эмулирует вызов getsockopt() на сокете, связанном с bpf_socket, который должен быть полным сокетом. Должен быть задан уровень level, на котором размещается опция, и имя optname для опции (см. man 2 getsockopt). Извлеченное значение сохраняется в структуре размера optlen, указанной opval.

Параметру bpf_socket следует иметь одно из указанных ниже значений.

  • структура bpf_sock_ops для BPF_PROG_TYPE_SOCK_OPS.

  • структура bpf_sock_ops для BPF_CGROUP_INET4_CONNECT и BPF_CGROUP_INET6_CONNECT.

Эта функция фактически реализует часть setsockopt() и поддерживает указанные ниже уровни.

IPPROTO_TCP

Поддерживает optname TCP_CONGESTION.

IPPROTO_IP

Поддерживает optname IP_TOS.

IPPROTO_IPV6

Поддерживает optname IPV6_TCLASS.

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_override_return

long bpf_override_return(struct pt_regs *regs, u64 rc)

Функция служит для вставки ошибок и использует kprobe для замены возвращаемого значения проверяемой функции, устанавливая код rc. Первым аргументом является контекст regs, в котором работает kprobe.

Эта функция работает путём установки программного счётчика (program counter или PC) на функцию переопределения, которая работает вместо проверяемой функции, которая в результате просто не вызывается. Функция подмены возвращает запрошенное значение.

Эта функция влияет на безопасность, поэтому для неё заданы ограничения. Функция доступна лишь в ядре, собранном с опцией CONFIG_BPF_KPROBE_OVERRIDE, и работает лишь для функций, имеющих тег ALLOW_ERROR_INJECTION в коде ядра.

Функция доступна лишь для архитектуры, поддерживающей опцию CONFIG_FUNCTION_ERROR_INJECTION (на момент написания этого документа эту функцию поддерживала лишь архитектура x86.

Функция возвращает 0.

bpf_sock_ops_cb_flags_set

long bpf_sock_ops_cb_flags_set(struct bpf_sock_ops *bpf_sock, int argval)

Пытается установить в поле bpf_sock_ops_cb_flags полного сокета TCP, связанного с bpf_sock_ops значение argval.

Основное назначение этой функции — определять, следует ли вызывать программы eBPF типа BPF_PROG_TYPE_SOCK_OPS в разных точках кода TCP. Программа одного типа может при необходимости менять значение при каждом соединении, когда соединение уже организовано. Это поле доступно для чтения напрямую, но для обновления должна использоваться данная функция, чтобы возвращалась ошибка, если программа eBPF пытается организовать обратный вызов (callback), не поддерживаемый текущим ядром.

Параметр argval является набором флагов из числа указанных ниже.

  • BPF_SOCK_OPS_RTO_CB_FLAG (тайм-аут повтора передачи).

  • BPF_SOCK_OPS_RETRANS_CB_FLAG (повтор передачи).

  • BPF_SOCK_OPS_STATE_CB_FLAG (смена состояния TCP).

  • BPF_SOCK_OPS_RTT_CB_FLAG (в каждом интервале RTT).

Поэтому данную функцию можно применять для очистки флага callback путём сброса (0) соответствующего бита, например, для отключения обратного вызова RTO

bpf_sock_ops_cb_flags_set(bpf_sock, bpf_sock->bpf_sock_ops_cb_flags & ~BPF_SOCK_OPS_RTO_CB_FLAG)

Ниже приведено несколько примеров, где можно было бы вызвать такую программу eBPF.

  • Срабатывание таймера RTO.

  • Повторная передача пакета.

  • Разрыв соединения.

  • Передача пакета.

  • Получение пакета.

Функция возвращает код -EINVAL, если сокет не является полным сокетом TCP, в иных случаях возвращается положительное число, содержащее биты, которые не удалось установить (0, если установлены все биты).

bpf_msg_redirect_map

long bpf_msg_redirect_map(struct sk_msg_buff *msg, struct bpf_map *map, u32 key, u64 flags)

Эта функция применяется в программах, реализующих правила на уровне сокета. Если сообщение msg можно пропустить (вердикт eBPF возвращает SK_PASS), оно перенаправляется в сокет, указанный map (типа BPF_MAP_TYPE_SOCKMAP) по индексу key. Для перенаправления можно использовать входные и выходные интерфейсы, наличие BPF_F_INGRESS в поле flags входной путь, отсутствие — выходной). Другие флаги не поддерживаются.

Функция возвращает SK_PASS при успехе, SK_DROP в случае ошибки.

bpf_msg_apply_bytes

long bpf_msg_apply_bytes(struct sk_msg_buff *msg, u32 bytes)

Для правил сокетов применяет вердикт программы eBPF к следующим bytes байтов сообщения msg.

Эту функцию можно применять, например, в следующих случаях.

  • Один системный вызов sendmsg() или sendfile() содержит несколько логических сообщений, которые программа eBPF должна прочитать и вынести вердикт.

  • Программе eBPF нужно прочитать лишь первые bytes байтов msg. Если содержимое сообщения велико, неоднократная организация и вызов программы eBPF для всех байтов ведут к значительным издержкам, даже если вердикт уже известен.

При вызове из программы eBPF функция устанавливает внутренний счётчик инфраструктуры BPF, который служит для применения последнего вердикта к следующим bytes байтов. Если значение bytes меньше текущего размера данных, обрабатываемых вызовом sendmsg() или sendfile(), первые bytes байтов будут переданы, а программа eBPF будет запушена снова с указателем на начало данных bytes + 1. Если bytes больше текущего размера обрабатываемых данных, вердикт eBPF будет применяться к нескольким вызовам sendmsg() или sendfile(), пока не будет обработано bytes байтов.

Если сокет закрывается с отличным от 0 внутренним счётчиком, это не создаёт проблемы, поскольку данные не буферизуются по bytes, а передаются по мере их получения.

Функция возвращает 0.

bpf_msg_cork_bytes

long bpf_msg_cork_bytes(struct sk_msg_buff *msg, u32 bytes)

Для правил сокетов функция предотвращает исполнение вердикта программы eBPF для сообщения msg, пока не будет накоплено bytes байтов.

Это можно использовать в случаях, когда требуется определённое число байтов для вынесения вердикта, даже если данные охватывают несколько вызовов sendmsg() или sendfile(). Крайним случаем будет повторяющийся вызов пользователем sendmsg() с 1-байтовыми сегментами сообщения. Очевидно, что это негативно влияет на производительность, но не запрещено. Если программе eBPF нужны bytes байтов для проверки заголовка, можно использовать эту функцию, чтобы программе eBPF не вызывалась снова, пока не будет накоплено bytes байтов.

Функция возвращает 0.

bpf_msg_pull_data

long bpf_msg_pull_data(struct sk_msg_buff *msg, u32 start, u32 end, u64 flags)

Для правил сокетов функция извлекает нелинейные данные из пользовательского пространства для msg, а также устанавливает указатели msg->data и msg->data_end на смещения start и end байтов в msg, respectively.

Если программа типа BPF_PROG_TYPE_SK_MSG запущена для msg, она может анализировать лишь данные, которые указатели (data, data_end) уже использовали. Для ловушек sendmsg() это будет, вероятно, первый элемент списка рассеяния (scatterlist). Однако для вызовов, полагающихся на обработчик sendpage (например, sendfile()), это будет диапазон (0, 0), поскольку данные используются совместно с пользовательским пространством и принятой по умолчанию целью является исключение возможности изменения данных пользователем, пока не будет принят вердикт eBPF. Эту функцию можно использовать для извлечения данных и установки указателей на начало и конец. Данные при необходимости будут копироваться (если они были нелинейны, а указатели начала и конца относятся к разным блокам).

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

Флаги зарезервированы на будущее и поле flags должно иметь значение 0.

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_bind

long bpf_bind(struct bpf_sock_addr *ctx, struct sockaddr *addr, int addr_len)

Привязывает сокет, указанный ctx к адресу addr размером addr_len. Это позволяет организовывать исходящие соединения с нужного адреса IP, что может быть полезно, например, когда всем процесса из cgroup следует использовать один адрес IP на хосте с несколькими адресами.

Функция работает с сокетами IPv4, IPv6, TCP, UDP, а поле addr->sa_family должно иметь значение AF_INET или AF_INET6. Рекомендуется указывать порт 0 (sin_port или sin6_port), что обеспечивает поведение в стиле IP_BIND_ADDRESS_NO_PORT и позволяет ядру эффективно выбирать свободный порт, пока квартет адресов и портов (4-tuple) уникален. Передача ненулевого значения может приводить к снижению производительности.

Функция возвращает 0 при успешном выполнении и отрицательное значение в случае ошибки.

bpf_xdp_adjust_tail

long bpf_xdp_adjust_tail(struct xdp_buff *xdp_md, int delta)

Смещает xdp_md->data_end на delta байтов. Функция позволяет увеличивать и сокращать «хвост» пакета. Для сокращения применяется отрицательное значение delta.

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

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_skb_get_xfrm_state

long bpf_skb_get_xfrm_state(struct sk_buff *skb, u32 index, struct bpf_xfrm_state *xfrm_state, u32 size, u64 flags)

Извлекает состояние XFRM (модель преобразований IP, см. man 8 ip-xfrm) с индексом index в «пути защиты» XFRM для skb. Извлеченное сохраняется в структуре bpf_xfrm_state размера size, указанной xfrm_state.

Флаги зарезервированы на будущее и поле flags должно иметь значение 0.

Функция доступна лишь для ядер, собранных с опцией CONFIG_XFRM.

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_get_stack

long bpf_get_stack(void *ctx, void *buf, u32 size, u64 flags)

Возвращает стек пользователя или ядра в предоставленный программой bpf буфер. Для этого функции нужен параметр ctx, указывающий контекст, в котором выполняется программа трассировки. Для сохранения трассировки стека программа bpf предоставляет буфер buf с неотрицательным размером size. Аргумент flags указывает число пропускаемых кадров стека (0 — 255) с маской BPF_F_SKIP_FIELD_MASK. В поле можно указать приведённые ниже флаги.

BPF_F_USER_STACK

Работать со стеком пользователя, а не ядра.

BPF_F_USER_BUILD_ID

Собирать buildid+offset вместо ips для пользовательского стека (применимо лишь с флагом BPF_F_USER_STACK).

Функция может собирать да PERF_MAX_STACK_DEPTH кадров из стека пользователя или ядра при наличии достаточно большого буфера. Этим ограничением может управлять программа sysctl и задавать предел вручную для работы с длинным пользовательским стеком (например, в программах Java). Команда установки значения имеет вид

# sysctl kernel.perf_event_max_stack=<new value>

Функция возвращает неотрицательное значение, не превышающее size, при успешном выполнении и отрицательное значение в случае ошибки.

bpf_skb_load_bytes_relative

long bpf_skb_load_bytes_relative(const void *skb, u32 offset, void *to, u32 len, u32 start_header)

Эта функция похожа на bpf_skb_load_bytes() и обеспечивает простой способ загрузить len байтов со смещением offset из пакета, связанного с skb, в буфер, указанный to. Отличие от bpf_skb_load_bytes() состоит в использовании пятого аргумента start_header, служащего для указания базового смещения для начала отсчёта. Параметр start_header может принимать одно из указанных ниже значений.

BPF_HDR_START_MAC

Базой смещения для загрузки данных является заголовок канального уровня в skb.

BPF_HDR_START_NET

Базой смещения для загрузки данных является заголовок сетевого уровня в skb.

В общем случае прямой доступ к пакету является предпочтительным методом доступа к данным, однако эта функция полезна, в частности, в фильтрах сокетов, где skb->data не всегда указывает начало заголовка MAC и прямой доступ к пакету невозможен.

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_fib_lookup

long bpf_fib_lookup(void *ctx, struct bpf_fib_lookup *params, int plen, u32 flags)

Выполняет поиск в FIB таблиц ядра с использованием параметров params. Если поиск удался и результат указывает, что кадр пересылается, выполняется поиск в таблице соседей для определения следующего узла (nexthop). При успехе (поиск в FIB указал пересылку и nexthop найден) в структуре bpf_fib_lookup возвращается адрес nexthop в ipv4_dst или ipv6_dst в зависимости от семейства адресов, smac указывает MAC-адрес выходного устройства, dmac — MAC-адрес nexthop, rt_metric — метрику маршрута (только для IPv4 и IPv6), а ifindex указывает индекс устройства nexthop из поиска в FIB. Аргумент plen указывает размер данных, передаваемых в структуре, а поле flags может включать 1 или 2 показанных ниже флага.

BPF_FIB_LOOKUP_DIRECT

Выполнять прямой поиск в таблице вместо полного поиска с применением правил FIB.

BPF_FIB_LOOKUP_OUTPUT

Выполнять поиск с точки зрения выхода (по умолчанию ищется с точки зрения входа).

Параметр ctx содержит структуру xdp_md для программ XDP или sk_buff для программ tc cls_act.

Функция возвращает отрицательное значение, если любой из аргументов не пригоден, 0 при успехе (пакет пересылается, nexthop существует) или один из кодов BPF_FIB_LKUP_RET_, указывающих, почему пакет не бул переслан и нужно содействие всего стека.

bpf_sock_hash_update

long bpf_sock_hash_update(struct bpf_sock_ops *skops, struct bpf_map *map, void *key, u64 flags)

Добавляет или обновляет отображение sockhash, указывающее сокеты. Параметр skops служит новым значением записи, связанной с ключом key. Поле flags содержит одно из указанных ниже значений.

BPF_NOEXIST

Запись для key должна присутствовать в map.

BPF_EXIST

Запись для key уже имеется в map.

BPF_ANY

Условия по наличию записи для key не заданы.

Если map имеет программы eBPF (parser и verdict), они будут наследоваться добавляемым сокетом. Если сокет уже связан с программами eBPF, это приведёт к ошибке.

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_msg_redirect_hash

long bpf_msg_redirect_hash(struct sk_msg_buff *msg, struct bpf_map *map, void *key, u64 flags)

Эта функция применяется в программах, реализующих правила на уровне сокета. Если сообщение msg можно пропустить (вердикт eBPF возвращает SK_PASS), оно перенаправляется в сокет, указанный map (типа BPF_MAP_TYPE_SOCKHASH) по индексу key. Для перенаправления можно использовать входные и выходные интерфейсы, наличие BPF_F_INGRESS в поле flags входной путь, отсутствие — выходной). Другие флаги не поддерживаются.

Функция возвращает SK_PASS при успехе, SK_DROP в случае ошибки.

bpf_sk_redirect_hash

long bpf_sk_redirect_hash(struct sk_buff *skb, struct bpf_map *map, void *key, u64 flags)

Эта функция применяется в программах, реализующих правила на skb уровня сокета. Если skb можно пропустить (вердикт eBPF возвращает SK_PASS), буфер перенаправляется в сокет, указанный map (типа BPF_MAP_TYPE_SOCKHASH) по индексу key. Для перенаправления можно использовать входные и выходные интерфейсы, наличие BPF_F_INGRESS в поле flags входной путь, отсутствие — выходной). Другие флаги не поддерживаются.

Функция возвращает SK_PASS при успехе, SK_DROP в случае ошибки.

bpf_lwt_push_encap

long bpf_lwt_push_encap(struct sk_buff *skb, u32 type, void *hdr, u32 len)

Инкапсулирует пакет, связанный с skb, в протокол L3 с использованием заголовка из буфера по адресу hdr размером len байтов. Параметр type указывает протокол и может принимать одно из указанных ниже значений.

BPF_LWT_ENCAP_SEG6

Инкапсуляция IPv6 с использованием заголовка SRH7 (struct ipv6_sr_hdr). Буфер hdr содержит лишь заголовок SRH, а заголовок IPv6 добавляет ядро.

BPF_LWT_ENCAP_SEG6_INLINE

Работает лишь с skb, содержащим пакет IPv6, и вставляет заголовок SRH (struct ipv6_sr_hdr) внутрь заголовка IPv6.

BPF_LWT_ENCAP_IP

Инкапсуляция IP (GRE, GUE, IPIP и т. п.). Внешним заголовком должен быть заголовок IPv4 или IPv6, за которым могут следовать дополнительные заголовки с общим размером всех добавляемых впереди заголовков до LWT_BPF_MAX_HEADROOM байтов. Отметим, что при skb_is_gso(skb) = true можно добавить не более 2 заголовков и при наличии внутреннего заголовка это должен быть заголовок GRE или UDP/GUE.

Типы BPF_LWT_ENCAP_SEG6* могут использовать программы BPF типа BPF_PROG_TYPE_LWT_IN, а тип BPF_LWT_ENCAP_IP — программы типов BPF_PROG_TYPE_LWT_IN и BPF_PROG_TYPE_LWT_XMIT.

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

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_lwt_seg6_store_bytes

long bpf_lwt_seg6_store_bytes(struct sk_buff *skb, u32 offset, const void *from, u32 len)

Сохраняет len байтов из адреса from в пакете, связанном с skb, по смещению offset. Эта функция может применяться лишь для изменения флагов, тега и TLV во внешнем заголовке IPv6 SRH.

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

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_lwt_seg6_adjust_srh

long bpf_lwt_seg6_adjust_srh(struct sk_buff *skb, u32 offset, s32 delta)

Корректирует размер, выделенный для TLV во внешнем заголовке IPv6 SRH пакета, связанного с skb, в позиции offset на delta байтов. Принимаются лишь смещения после сегментов, а значение delta может быть положительным (расширение) или отрицательным (сокращение).

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

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_lwt_seg6_action

long bpf_lwt_seg6_action(struct sk_buff *skb, u32 action, void *param, u32 param_len)

Применяет действие IPv6 Segment Routing типа action к пакету, связанному с skb. Каждое действие содержит параметры размером param_len байтов, размещённые по адресу param. Действием может быть 1 из указанных ниже.

SEG6_LOCAL_ACTION_END_X

End.X — конечная точка с L3 cross-connect, param указывает структуру in6_addr.

SEG6_LOCAL_ACTION_END_T

End.T — конечная точка с конкретным результатом поиска в таблице IPv6, param указывает int.

SEG6_LOCAL_ACTION_END_B6

End.B6 — конечная точка привязана к правилу SRv6, param указывает структуру ipv6_sr_hdr.

SEG6_LOCAL_ACTION_END_B6_ENCAP

End.B6.Encap — конечная точка привязана к правилу инкапсуляции SRv6, param указывает структуру ipv6_sr_hdr.

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

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_rc_repeat

long bpf_rc_repeat(void *ctx)

Эта функция применяется в программах, реализующих декодирование IR8, для информирования об успешном декодировании повторяющегося сообщения от кнопки (key). Это задерживает генерацию события key up (отпускание кнопки) для созданного ранее события key down (нажатие кнопки).

Некоторые протоколы IR, такие как NEC, включают специальное сообщение IR для повтора последнего нажатия кнопки, когда кнопка удерживается.

Параметру ctx следует указывать на выборку, переданную в программу.

Функция работает только с ядрами, собранными с опцией конфигурации CONFIG_BPF_LIRC_MODE2 = y.

Функция возвращает 0.

bpf_rc_keydown

long bpf_rc_keydown(void *ctx, u32 protocol, u64 scancode, u32 toggle)

Эта функция применяется в программах, реализующих декодирование IR, для информирования об успешном декодировании нажатия кнопки со скан-кодом scancode, имеющей значение toggle в данном протоколе protocol. Скан-код транслируется в код кнопки с помощью отображения rc и сообщаться на вход как нажатие кнопки. По истечении определённого времени генерируется событие key up. Этот период можно расширить повторным вызовом bpf_rc_keydown() с теми же значениями или вызовом bpf_rc_repeat().

Некоторые протоколы используют бит переключения (toggle) на случай, когда кнопка была отпущена и нажата снова в интервале между сканированием.

В параметре ctx следует указывать выборку lirc, переданную в программу, protocol — декодированный номер протокола (см. предопределённые значения в enum rc_proto).

Функция работает только с ядрами, собранными с опцией конфигурации CONFIG_BPF_LIRC_MODE2 = y.

Функция возвращает 0.

bpf_skb_cgroup_id

u64 bpf_skb_cgroup_id(struct sk_buff *skb)

Возвращает идентификатор cgroup v2 для сокета, связанного с skb. Функция похожа на bpf_get_cgroup_classid() для cgroup v1, предоставляя идентификатор, которых может применяться для сопоставления или поиска в отображении, например, для реализации правил. Идентификатор cgroup v2 данного пути в иерархии раскрывается в пользовательское пространство через f_handle API, чтобы получить тот же 64-битовый идентификатор.

Эту функцию можно применять на выходном пути TC, но она непригодна для входного пути. Функция доступна лишь для ядер, собранных с конфигурационной опцией CONFIG_SOCK_CGROUP_DATA.

Функция возвращает значение идентификатор или 0, если идентификатор не найден.

bpf_get_current_cgroup_id

u64 bpf_get_current_cgroup_id(void)

Функция возвращает 64-битовое целое число, содержащее текущий идентификатор cgroup с которой работает текущая задача.

bpf_get_local_storage

void *bpf_get_local_storage(void *map, u64 flags)

Возвращает указатель на локальную область хранения, тип и размер которой задаёт аргумент map. Назначение параметра flags зависит от типа отображения и для локального хранилища должно иметь значение 0.

В зависимости от типа программы BPF локальное хранилище может совместно использоваться несколькими экземплярами программы BPF, работающими одновременно. Пользователю следует озаботиться вопросами синхронизации, например, используя инструкцию BPF_STX_XADD для изменения общих данных.

bpf_sk_select_reuseport

long bpf_sk_select_reuseport(struct sk_reuseport_md *reuse, struct bpf_map *map, void *key, u64 flags)

Выбирает сокет SO_REUSEPORT из отображения map BPF_MAP_TYPE_REUSEPORT_ARRAY, проверяя его на соответствие входящему запросу.

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_skb_ancestor_cgroup_id

u64 bpf_skb_ancestor_cgroup_id(struct sk_buff *skb, int ancestor_level)

Возвращает идентификатор cgroup v2, являющийся предком cgroup, связанной с skb на уровне ancestor_level. Корнем cgroup является ancestor_level = 0 и каждый шаг вниз по иерархии инкрементирует уровень. Если ancestor_level совпадает с уровнем cgroup, связанной с skb, возвращаемое значение будет совпадать с результатом bpf_skb_cgroup_id().

Функция полезна для реализации правил, основанных на cgroup, которые в иерархии выше cgroup, связанной с skb.

Возвращаемый формат и ограничения функции совпадают с заданными для bpf_skb_cgroup_id().

Функция возвращает идентификатор или 0, если идентификатор не найден.

bpf_sk_lookup_tcp

struct bpf_sock *bpf_sk_lookup_tcp(void *ctx, struct bpf_sock_tuple *tuple, u32 tuple_size, u64 netns, u64 flags)

Отыскивает сокет TCP, соответствующий tuple, с возможностью указать также дочернее простанство имён сети netns. Найденное значение должно проверяться и в случае непустого (не NULL) значения освобождаться через bpf_sk_release(). Параметру ctx следует указывать контекст программы, такой как skb или socket (в зависимости от применяемой ловушки). Это позволяет определить базовое пространство сетевых имён для поиска. Параметр tuple_size должен принимать значение sizeof(tuple->ipv4) для поиска сокета IPv4 или sizeof(tuple->ipv6) для сокета IPv6.

Если параметр netns является отрицательным 32-битовым целым числом со знаком, для поиска используется таблица в netns, связанном с ctx. Для ловушек TC это netns устройства в skb, для ловушек сокетов — netns сокета. Иные 32-битовые значения netns указывают идентификатор netns относительно пространства netns, связанного с ctx. Значения netns, выходящие за рамки 32 битов, зарезервированы на будущее. Все значения флагов являются резервными и поле flags должно иметь значение 0.

Функция доступна только для ядер, собранных с опцией CONFIG_NET.

Функция возвращает указатель на структуру bpf_sock или NULL в случае ошибки. Для сокетов с опцией reuseport структура bpf_sock берётся из reuse->socks[] с использованием хэш-значения кортежа адресов и портов (tuple).

bpf_sk_lookup_udp

struct bpf_sock *bpf_sk_lookup_udp(void *ctx, struct bpf_sock_tuple *tuple, u32 tuple_size, u64 netns, u64 flags)

Отыскивает сокет UDP, соответствующий tuple, с возможностью указать также дочернее простанство имён сети netns. Найденное значение должно проверяться и в случае непустого (не NULL) значения освобождаться через bpf_sk_release(). Параметру ctx следует указывать контекст программы, такой как skb или socket (в зависимости от применяемой ловушки). Это позволяет определить базовое пространство сетевых имён для поиска. Параметр tuple_size должен принимать значение sizeof(tuple->ipv4) для поиска сокета IPv4 или sizeof(tuple->ipv6) для сокета IPv6.

Если параметр netns является отрицательным 32-битовым целым числом со знаком, для поиска используется таблица в netns, связанном с ctx. Для ловушек TC это netns устройства в skb, для ловушек сокетов — netns сокета. Иные 32-битовые значения netns указывают идентификатор netns относительно пространства netns, связанного с ctx. Значения netns, выходящие за рамки 32 битов, зарезервированы на будущее. Все значения флагов являются резервными и поле flags должно иметь значение 0.

Функция доступна только для ядер, собранных с опцией CONFIG_NET.

Функция возвращает указатель на структуру bpf_sock или NULL в случае ошибки. Для сокетов с опцией reuseport структура bpf_sock берётся из reuse->socks[] с использованием хэш-значения кортежа адресов и портов (tuple).

bpf_sk_release

long bpf_sk_release(struct bpf_sock *sock)

Освобождает ссылку, указанную параметром sock, который должен быть ненулевым (не NULL) указателем, возвращенным bpf_sk_lookup_xxx().

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_map_push_elem

long bpf_map_push_elem(struct bpf_map *map, const void *value, u64 flags)

Вталкивает значение элемента value в отображение map. Поле flags содержит BPF_EXIST (если очередь или стек заполнены, самый старый элемент удаляется для освобождения места).

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_map_pop_elem

long bpf_map_pop_elem(struct bpf_map *map, void *value)

Выталкивает элемент из отображения map.

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_map_peek_elem

long bpf_map_peek_elem(struct bpf_map *map, void *value)

Извлекает элемент отображения map, не удаляя его.

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_msg_push_data

long bpf_msg_push_data(struct sk_msg_buff *msg, u32 start, u32 len, u64 flags)

Для правил сокета вставляет len байтов в msg по смещению start. Программа типа BPF_PROG_TYPE_SK_MSG, работающая с msg, может захотеть добавить туда метаданные или опции, которые позднее можно прочитать и использовать в любой ловушке BPF нижележащего уровня.

Эта функция может вызывать ошибку при незватке памяти (отказ fails) и программа BPF будет получать соответствующее сообщение, которое она должна обработать.

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_msg_pop_data

long bpf_msg_pop_data(struct sk_msg_buff *msg, u32 start, u32 len, u64 flags)

Функция удаляет len из msg, начиная с байта start. Это может вызывать ошибку ENOMEM, если требуется выделение и копирование по причине заполнения кольцевого буфера. Однако функция будет пытаться избежать выделения памяти, если это возможно. Другие ошибки могут возникать, если непригодны входные параметры, например, байт start не является действительной частью данных msg payload или выталкиваемое значение слишком велико.

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_rc_pointer_rel

long bpf_rc_pointer_rel(void *ctx, s32 rel_x, s32 rel_y)

Функция применяется в программах, реализующих декодирование IR, для информирования об успешном декодировании перемещения указателя. Параметру ctx следует указывать выборку lirc, передаваемую в программу.

Функция доступна лишь для ядер, собранных с опцией конфигурации CONFIG_BPF_LIRC_MODE2 = y.

Функция возвращает 0.

bpf_spin_lock

long bpf_spin_lock(struct bpf_spin_lock *lock)

Устанавливает блокировку (spinlock), представленную указателем lock, которая хранится как часть значения отображения. Снятие блокировки позволяет без опаски изменить остальные поля в этом значении. Блокировка затем может (и должна) быть снята вызовом функции bpf_spin_unlock(lock).

С блокировками в программах BPF связано множество ограничений, указанных ниже.

  • Объекты bpf_spin_lock могут находиться лишь внутри отображений типов BPF_MAP_TYPE_HASH и BPF_MAP_TYPE_ARRAY (список может быть расширен в будущем).

  • Обязательно описание отображения в формате BTF.

  • Программа BPF может выполнять в каждый момент времени лишь 1 блокировку, поскольку наличие нескольких может приводить к зависанию (dead lock).

  • На элемент отображения разрешается лишь 1 структура bpf_spin_lock.

  • При снятой блокировке вызовы (из BPF в BPF или функцию-помощник) не разрешены.

  • Вызовы инструкций BPF_LD_ABS и BPF_LD_IND не разрешены внутри области с блокировкой.

  • Программа BPF должна вызывать функцию bpf_spin_unlock() для снятия блокировки на всех путях вызова до завершения своей работы.

  • Программа BPF может обращаться к структуре bpf_spin_lock только через функции bpf_spin_lock() и bpf_spin_unlock(). Загрузка или сохранение данных с поле lock структуры bpf_spin_lock в отображении не допускается.

  • Для использования функции bpf_spin_lock() BTF-описание значения отображения должно быть структурой, включающей поле anyname на верхнем уровне. Вложенная блокировка внутри другой структуры не разрешена.

  • Поле lock структуры bpf_spin_lock в отображении должно быть выровнено по границе 4 байтов в значении.

  • Вызов BPF_MAP_LOOKUP_ELEM не копирует поле bpf_spin_lock в пользовательское пространство.

  • Вызов BPF_MAP_UPDATE_ELEM или обновление из программы BPF не обновляет поле bpf_spin_lock.

  • bpf_spin_lock не может размещаться в стеке или внутри сетевого пакета (только в значениях отображений).

  • bpf_spin_lock доступна только пользователю root.

  • Программы трассировки и фильтров сокета не могут применять bpf_spin_lock() из-за недостаточных проверок вытеснения (в будущем это может быть разрешено).

  • bpf_spin_lock не разрешается во внутренних (вложенных) отображениях (map-in-map).

Функция возвращает 0.

bpf_spin_unlock

long bpf_spin_unlock(struct bpf_spin_lock *lock)

Снимает блокировку lock, установленную функций bpf_spin_lock(lock).

Функция возвращает 0.

bpf_sk_fullsock

struct bpf_sock *bpf_sk_fullsock(struct bpf_sock *sk)

Получает указатель на структуру bpf_sock для обеспечения возможности доступа ко всем её полям.

Функция возвращает указатель на структуру bpf_sock при успехе и NULL в случае ошибки.

bpf_tcp_sock

struct bpf_tcp_sock *bpf_tcp_sock(struct bpf_sock *sk)

Получает указатель на структуру bpf_tcp_sock по указателю на структуру bpf_sock.

Функция возвращает указатель на структуру bpf_tcp_sock при успехе и NULL в случае ошибки.

bpf_skb_ecn_set_ce

long bpf_skb_ecn_set_ce(struct sk_buff *skb)

Устанавливает в поле ECN заголовка IP значение CE9, если текущим значением является ECT10. В ином случае не делает ничего. Функция работает с IPv6 и IPv4.

Функция возвращает 1, если флаг CE установлен или уже был в заголовке, 0 — в ином случае.

bpf_get_listener_sock

struct bpf_sock *bpf_get_listener_sock(struct bpf_sock *sk)

Возвращает указатель на структуру bpf_sock в состоянии TCP_LISTEN. Вызов bpf_sk_release() не нужен и не разрешен.

Функция возвращает на структуру bpf_sock при успехе и NULL в случае ошибки.

bpf_skc_lookup_tcp

struct bpf_sock *bpf_skc_lookup_tcp(void *ctx, struct bpf_sock_tuple *tuple, u32 tuple_size, u64 netns, u64 flags)

Отыскивает сокет TCP, соответствующий tuple, с возможностью указать также дочернее простанство имён сети netns. Найденное значение должно проверяться и в случае непустого (не NULL) значения освобождаться через bpf_sk_release().

Эта функция идентична bpf_sk_lookup_tcp(), но возвращает также сокеты timewait и request. Для доступа к полной структуре служат функции bpf_sk_fullsock() и bpf_tcp_sock().

Функция доступна только для ядер, собранных с опцией CONFIG_NET.

Функция возвращает указатель на структуру bpf_sock или NULL в случае ошибки. Для сокетов с опцией reuseport структура bpf_sock берётся из reuse->socks[] с использованием хэш-значения кортежа адресов и портов (tuple).

bpf_tcp_check_syncookie

long bpf_tcp_check_syncookie(struct bpf_sock *sk, void *iph, u32 iph_len, struct tcphdr *th, u32 th_len)

Проверяет, содержится ли в iph и th действительное подтверждение SYN cookie ACK для слушающего сокета в sk. Параметр iph указывает начало заголовка IPv4 или IPv6, а iph_len содержит sizeof(struct iphdr) или (struct ip6hdr). Параметр th указывает начало заголовка TCP, а th_len содержит sizeof(struct tcphdr).

Функция возвращает 0, если iph и th содержат действительное подтверждение SYN cookie ACK, и отрицательное значение ошибки в ином случае.

bpf_sysctl_get_name

long bpf_sysctl_get_name(struct bpf_sysctl *ctx, char *buf, size_t buf_len, u64 flags)

Получает имя sysctl в /proc/sys/ и копирует его в предоставленный программой буфер buf размером buf_len. Если размер буфера отличается от 0, он всегда завершается NUL-символом. Если flags = 0, копируется полное имя (например, net/ipv4/tcp_mem), а значение BPF_F_SYSCTL_BASE_NAME позволяет копировать лишь базовое имя (например, tcp_mem).

Функция возвращает число скопированных символов (без учёта завершающего NUL) или -E2BIG, если буфер оказался мал (он все равно будет включать часть имени).

bpf_sysctl_get_current_value

long bpf_sysctl_get_current_value(struct bpf_sysctl *ctx, char *buf, size_t buf_len)

Получает текущее значение sysctl, как оно представлено в /proc/sys (включая перевод строки и т. п.), и копирует его целиком в предоставленный программой буфер buf размером buf_len. Если размер буфера отличается от 0, он всегда завершается NUL-символом.

Функция возвращает число скопированных символов (без учёта завершающего NUL), -E2BIG, если буфер оказался мал (он все равно будет включать часть имени), или -EINVAL, если текущее значение было недоступно, например потому, что sysctl не инициализирована и чтение возвратило -EIO.

bpf_sysctl_get_new_value

long bpf_sysctl_get_new_value(struct bpf_sysctl *ctx, char *buf, size_t buf_len)

Получает новое значение, записываемое пользовательским пространством в sysctl (до фактической записи), и копирует его как строку в предоставленный программой буфер buf размером buf_len. Пользовательское пространство может записать новое значение не в начало файла.

Если размер буфера отличается от 0, он всегда завершается NUL-символом.

Функция возвращает число скопированных символов (без учёта завершающего NUL), -E2BIG, если буфер оказался мал (он все равно будет включать часть имени), или -EINVAL, если sysctl читается.

bpf_sysctl_set_new_value

long bpf_sysctl_set_new_value(struct bpf_sysctl *ctx, const char *buf, size_t buf_len)

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

Функция возвращает 0 при успехе, -E2BIG, если значение buf_len слишком велико, и -EINVAL, если sysctl читается.

bpf_strtol

long bpf_strtol(const char *buf, size_t buf_len, u64 flags, long *res)

Преобразует начальную часть строки из буфера buf размером buf_len в длинное целое число с заданной базой и сохраняет результат в res. Строка может содержать в начале произвольное число пробелов (см. man 3 isspace), за которыми может следовать 1 символ ‘-‘. Пять младших битов параметра flags указывают базу для числа, атальные биты флагов не используются. База должна иметь значение 8, 10, 16 или 0, чтобы определять её автоматически, подобно strtol в пользовательском пространстве.

Функция возвращает число извлеченных символов, которое должно быть положительным и не больше buf_len. Если не были найдены пригодные цифры или представлена неподдерживаемая база, возвращается ошибка -EINVAL, если значение выходит за пределы диапазона — -ERANGE.

bpf_strtoul

long bpf_strtoul(const char *buf, size_t buf_len, u64 flags, unsigned long *res)

Преобразует начальную часть строки из буфера buf размером buf_len в длинное целое число без знака с заданной базой и сохраняет результат в res. Строка может содержать в начале произвольное число пробелов (см. man 3 isspace). Пять младших битов параметра flags указывают базу для числа, атальные биты флагов не используются. База должна иметь значение 8, 10, 16 или 0, чтобы определять её автоматически, подобно strtoul в пользовательском пространстве.

Функция возвращает число извлеченных символов, которое должно быть положительным и не больше buf_len. Если не были найдены пригодные цифры или представлена неподдерживаемая база, возвращается ошибка -EINVAL, если значение выходит за пределы диапазона — -ERANGE.

bpf_sk_storage_get

void *bpf_sk_storage_get(struct bpf_map *map, struct bpf_sock *sk, void *value, u64 flags)

Получает локальное хранилище bpf (bpf-local-storage) из sk.

Логически это можно считать получением значения из map с sk в качестве ключа. С этой точки зрения действие функции не сильно отличается от bpf_map_lookup_elem(map, &sk), но данная функция требует, чтобы ключ был полным сокетом, а отображение жолжно иметь тип BPF_MAP_TYPE_SK_STORAGE.

Значение сохраняется локально в sk, а не в map. Отображение map используется как «тип» bpf-local-storage. По этому типу (т. е. map) выполняется поиск среди локальных хранилишщ, содержащихся в sk.

Может использоваться необязательное поле flags (BPF_SK_STORAGE_GET_F_CREATE) для создания нового bpf-local-storage, если хранилища ещё нет. Параметр value может использоваться вместе с BPF_SK_STORAGE_GET_F_CREATE для задания начального значения bpf-local-storage. При value = NULL новое хранилише bpf-local-storage инициализируется нулем.

Функция возвращает A bpf-local-storage pointer is returned on success. NULL if not found or there was an error in adding a new bpf-local-storage.

bpf_sk_storage_delete

long bpf_sk_storage_delete(struct bpf_map *map, struct bpf_sock *sk)

Удаляет bpf-local-storage из sk.

Функция возвращает 0 при успеше и -ENOENT, если хранилище bpf-local-storage не найдено.

bpf_send_signal

long bpf_send_signal(u32 sig)

Передаёт сигнал sig процессу текущей задачи. Сигнал может доставляться любому потоку (thread) процесса.

Функция возвращает 0 при успешном выполнении или постановке в очередь. Ошибка -EBUSY возвращается, если рабочая очередь под nmi заполнена, -EINVAL при непригодности sig, -EPERM, если нет полномочий на отправку sig, -EAGAIN, если программа bpf может повторить попытку.

bpf_tcp_gen_syncookie

s64 bpf_tcp_gen_syncookie(struct bpf_sock *sk, void *iph, u32 iph_len, struct tcphdr *th, u32 th_len)

Пытается выдать SYN cookie для пакета с соответствующими заголовками IP/TCP (iph и th), на слушающем сокете в sk. Параметр iph указывает начало заголовка IPv4 или IPv6, а iph_len содержит sizeof(struct iphdr) или sizeof(struct ip6hdr). Параметр th указывает начало заголовка TCP, а th_len — его размер.

При успешном выполнении функция возвращает в 32 младших битах созданное значение SYN cookie, в следующих 16 — значение MSS для этого cookie, а последние 16 битов не используются. При отказе возвращается одно из приведённых ниже значений.

  • -EINVAL — SYN cookie не удалось выдать из-за ошибки.

  • -ENOENT — SYN cookie не следует выдавать (нет SYN flood).

  • -EOPNOTSUPP — конфигурация ядра не разрешает SYN cookie.

  • -EPROTONOSUPPORT — версия IP в пакет отличается от 4 и 6.

bpf_skb_output

long bpf_skb_output(void *ctx, struct bpf_map *map, u64 flags, void *data, u64 size)

Записывает необработанные данные data (blob) в специальное событие BPF, удерживаемое отображением map типа BPF_MAP_TYPE_PERF_EVENT_ARRAY. Это собцтие должно имет атрибут PERF_SAMPLE_RAW как sample_type, PERF_TYPE_SOFTWARE как type и PERF_COUNT_SW_BPF_OUTPUT как config.

Параметр flags служит для указания индекса в map, по которому нужно поместить значение, с применением маски BPF_F_INDEX_MASK. Как вариант, можно установить BPF_F_CURRENT_CPU, чтобы указать использование индекса текущего CPU. Значение для записи (размером size) передаётся через стек eBPF и указывается параметром data. Параметр ctx является указателем на структуру sk_buff в ядре.

Эта функция похожа на bpf_perf_event_output(), но ограничена программами BPF raw_tracepoint.

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_probe_read_user

long bpf_probe_read_user(void *dst, u32 size, const void *unsafe_ptr)

Пытается безопасно считать size байтов по адресу unsafe_ptr в пользовательском пространстве и сохранить их в dst.

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_probe_read_kernel

long bpf_probe_read_kernel(void *dst, u32 size, const void *unsafe_ptr)

Пытается безопасно считать size байтов по адресу unsafe_ptr в пространстве ядра и сохранить их в dst.

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_probe_read_user_str

long bpf_probe_read_user_str(void *dst, u32 size, const void *unsafe_ptr)

Копирует строку с NUL-символом в конце с небезопасного пользовательского адреса unsafe_ptr в dst. В параметре size следует учитывать завершающий NUL-байт. Если размер строки меньше size, целевой объект не дополняется байтами NUL. Если размер строки больше size, из неё копируется size-1 байтов и к ним добавляется в конце NUL-байт.

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

SEC("kprobe/sys_open")
void bpf_sys_open(struct pt_regs *ctx)
{
	char buf[PATHLEN]; // Для PATHLEN задано значение 256
       int res = bpf_probe_read_user_str(buf, sizeof(buf), ctx->di	
	// Извлекается buf, например, переносом в пользовательское
       	// пространство через bpf_perf_event_output(); результат res
       	// (размер строки) может применяться как размер события
       	// после проверки его границ.
}

При использовании bpf_probe_read_user() потребовалось бы указывать размер строки во время компиляции, что часто приводило бы к копированию излишнего объёма памяти.

Другим полезным вариантом применения является анализ отдельных аргументов процесса или переменных среды при перемещении по current->mm->arg_start и current->mm->env_start. Используя значение этой функции можно быстро выполнить операцию с правильным смещением области памяти.

Функция возвращает при успехе размер строки с учётом символа NUL или отрицательное значение при ошибке.

bpf_probe_read_kernel_str

long bpf_probe_read_kernel_str(void *dst, u32 size, const void *unsafe_ptr)

Копирует строку с NUL-символом в конце с небезопасного адреса ядра unsafe_ptr в dst. Семантика этой функции не отличается от семантики bpf_probe_read_user_str().

Функция возвращает при успехе размер строки с учётом символа NUL или отрицательное значение при ошибке.

bpf_tcp_send_ack

long bpf_tcp_send_ack(void *tp, u32 rcv_nxt)

Передаёт TCP ACK (tcp-ack). Параметр tp указывает структуру ядра tcp_sock, rcv_nxt — номер ack_seq для отправки.

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_send_signal_thread

long bpf_send_signal_thread(u32 sig)

Передаёт сигнал sig для потока, связанного с текущей задачей.

Функция возвращает 0 при успешной передаче или постановке в очередь. Ошибка -EBUSY возвращается, если очередь под nmi заполнена, -EINVAL, если сигнал sig недействителен, -EPERM, если нет полномочий на отправку sig, и -EAGAIN, если программа bpf может повторить попытку.

bpf_jiffies64

u64 bpf_jiffies64(void)

Возвращает 64-битовое число jiffy.

bpf_read_branch_records

long bpf_read_branch_records(struct bpf_perf_event_data *ctx, void *buf, u32 size, u64 flags)

Для программы eBPF, связанной с событием perf event, функция извлекает записи ветвей (struct perf_branch_entry), связанной с ctx, и сохраняет их в буфере, указанном параметром buf и имеющем размер до size байтов.

В поле flags можно указать значение BPF_F_GET_BRANCH_RECORDS_SIZE, чтобы функция возвращала число байтов, требуемых для сохранения всех записей ветвей. В этом случае можно указать buf = NULL.

Функция при успешном завершении возвращает число байтов, записанных в buf. При ошибке возвращается отрицательный код:

  • -EINVAL, если аргументы недействительны или значение size не кратно sizeof(struct perf_branch_entry);

  • -ENOENT, если архитектура не поддерживает записи ветвей.

bpf_get_ns_current_pid_tgid

long bpf_get_ns_current_pid_tgid(u64 dev, u64 ino, struct bpf_pidns_info *nsdata, u32 size)

При успешном выполнении функция возвращает 0, а значения pid и tgid, видимые из текущего пространства имён, возвращаются в структуре nsdata.

Функция возвращает 0 в случае успеха или один из отрицательных кодов ошибок, указанных ниже:

  • -EINVAL, если представленные dev и inum не соответствуют dev_t и inode с nsfs текущей задачи или при преобразовании dev в dev_t потеряны старшие биты;

  • -ENOENT, если pidns не существует для текущей задачи.

bpf_xdp_output

long bpf_xdp_output(void *ctx, struct bpf_map *map, u64 flags, void *data, u64 size)

Записывает необработанные данные data (blob) в специальное событие BPF, содержащееся в map типа BPF_MAP_TYPE_PERF_EVENT_ARRAY. Это событие perf должно иметь атрибуты — PERF_SAMPLE_RAW как sample_type, PERF_TYPE_SOFTWARE как type, PERF_COUNT_SW_BPF_OUTPUT как config.

Параметр flags служит для указания индекса в map, по которому нужно поместить значение, с применением маски BPF_F_INDEX_MASK. Как вариант, можно установить BPF_F_CURRENT_CPU, чтобы указать использование индекса текущего CPU. Значение для записи (размером size) передаётся через стек eBPF и указывается параметром data. Параметр ctx является указателем на структуру xdp_buff в ядре.

Эта функция похода на bpf_perf_event_output(), но ограничена программами BPF raw_tracepoint.

При успешном выполнении функция возвращает 0, при отказе — отрицательное значение.

bpf_get_netns_cookie

u64 bpf_get_netns_cookie(void *ctx)

Извлекает cookie (создано ядром) из сетевого пространства имён, в которым связан параметр ctx. Значение cookie сетевого пространства имён не меняется в течение срока действия и является глобальным идентификатором, который можно считать уникальным. Если ctx = NULL, функция возвращает cookie для исходного сетевого пространства имён. Само значение cookie очень похоже на возвращаемое функцией bpf_get_socket_cookie(), но относится к пространству имён сети, а не сокета.

Функция возвращает 8-байтовое неинтерпретируемое число.

bpf_get_current_ancestor_cgroup_id

u64 bpf_get_current_ancestor_cgroup_id(int ancestor_level)

Возвращает идентификатор cgroup v2, которая является предком cgroup, связанной с текущей задачей, на уровне ancestor_level. Корнем cgroup является ancestor_level 0 и каждый шаг вниз по иерархии увеличивает уровень. Если ancestor_level совпадает с уровнем cgroup, связанной с текущей задачей, возвращаемое значение будет совпадать с результатом вызова bpf_get_current_cgroup_id().

Функция полезна для реализации правил, основанных на cgroup, которые в иерархии выше cgroup, непосредственно связанной с текущей задачей.

Формат возвращаемого идентификатора и ограничения функции те же, что и для bpf_get_current_cgroup_id().

Функция возвращает значение идентификатора или 0, если идентификатор не извлечён.

bpf_sk_assign

long bpf_sk_assign(struct sk_buff *skb, struct bpf_sock *sk, u64 flags)

Функция перезагружается в зависимости от типа программы BPF (описание пригодно для BPF_PROG_TYPE_SCHED_CLS и BPF_PROG_TYPE_SCHED_ACT).

Функция присваивает значение sk переменной skb. В сочетании с подходящей конфигурацией маршрутизации для приёма пакета в направлении сокета это приведёт к длставке skb в указанный сокет. Последующее перенаправление skb через bpf_redirect(), bpf_clone_redirect() или иные методы вне BPF могут помешать доставке в сокет.

Эта операция действительна лишь на входном пути TC.

Аргумент flags должен иметь значение 0.

Функция возвращает 0 при успехе и отрицательный код при ошибке:

  • -EINVAL, если заданные флаги не поддерживаются;

  • -ENOENT, если сокет недоступен для назначения;

  • -ENETUNREACH, если сокет недоступен (ошбка netns);

  • -EOPNOTSUPP, если операция не поддерживается, например, вызов извне входа TC;

  • -ESOCKTNOSUPPORT, если тип сокета не поддержтвается (reuseport).

bpf_sk_assign

long bpf_sk_assign(struct bpf_sk_lookup *ctx, struct bpf_sock *sk, u64 flags)

Функция перезагружается в зависимости от типа программы BPF (описание пригодно для BPF_PROG_TYPE_SK_LOOKUP).

Функция выбирает sk как результат поиска сокета.

Для успешного выполнения операции сокет должен быть совместим с описанием пакета, представленным объектом ctx.

Протокол L4 (IPPROTO_TCP или IPPROTO_UDP) должен совпадать точно. Семейства адресов IP (AF_INET или AF_INET6) должны быть совместимыми, т. е. для сокетов IPv6, поддерживающих не только v6, могут быть выбраны пакеты IPv4.

Выбирать можно только слушающие сокеты TCP (listener) и не подключенные сокеты UDP. Параметр sk может иметь значение NULL для сброса прежнего выбора.

Аргумент flags может включать сочетание указанных ниже флагов.

  • BPF_SK_LOOKUP_F_REPLACE для переопределения прежнего выбора сокета, который могла сделать программа BPF, работавшая ранее.

  • BPF_SK_LOOKUP_F_NO_REUSEPORT для пропуска распределения нагрузки в группе reuseport для выбранного сокета.

При успехе ctx->sk будет указывать выбранный сокет.

Функция возвращает 0 при успехе и отрицательный код при ошибке:

  • -EAFNOSUPPORT, если семейство адресов сокета (sk->family) несовместимо с семейством пакета (ctx->family);

  • -EEXIST, если сокет уже выбран (возможно, другой программой), а флаг BPF_SK_LOOKUP_F_REPLACE не задан;

  • -EINVAL, если заданные флаги не поддерживаются;

  • -EPROTOTYPE, если протокол L4 в сокете (sk->protocol) не соответствует протоколу в пакете (ctx->protocol);

  • -ESOCKTNOSUPPORT, если сокет не находится в разрешенном состоянии (прослущивающий сокет TCP или отсоединенный сокет UDP).

bpf_ktime_get_boot_ns

u64 bpf_ktime_get_boot_ns(void)

Возвращает время, прошедшее с момента загрузки системы (в наносекундах) — текущее значение ktime, включая время, когда система была приостановлена (см. clock_gettime(CLOCK_BOOTTIME)).

bpf_seq_printf

long bpf_seq_printf(struct seq_file *m, const char *fmt, u32 fmt_size, const void *data, u32 data_len)

Функция использует seq_file seq_printf() для вывода строки формата. Параметр m представляет seq_file, fmt и fmt_size служат для строки формата, data и data_len — аргументы строки формата. Параметр data — это массив u64 и соответствующие значения строки формата сохраняются в массиве. Для строк и указаталей, где происходит обращение к указанным элементам в массиве data сохраняются лишь указатели. Поле data_len указывает ращмер данных в байтах.

Для чтения памяти ядра требуются форматы %s, %p{i,I}{4,6}. При таком чтении могут возникать ошибки из-за неверного адреса или верного адреса, требующего существенного отказа в памяти. Если отказ при чтении памяти ядра возникает, строка %s будет пустой, а адрес ip для %p{i,I}{4,6} будет иметь значение 0. Отсутствие возврата ошибки в программу bpf согласуестся с поведением функции bpf_trace_printk().

Функция возвращает 0 при успешном выполнении и отрицательный код при ошибке:

  • -EBUSY, если буфер копирования памяти для CPU занят (можно повторить попытку, вернув 1 из программы bpf);

  • -EINVAL, если аргумент недействителен или fmt не поддерживается (недействителен);

  • -E2BIG, если fmt содержит слишком много указателей формата;

  • -EOVERFLOW, если возникает переполнение (попытка повторяется с тем же объектом).

bpf_seq_write

long bpf_seq_write(struct seq_file *m, const void *data, u32 len)

Функция использует seq_file seq_write() для записи данных. Параметр m представляет seq_file, data и len — данные для записи.

Функция возвращает 0 при успешном выполнении и отрицательный код при ошибке: -EOVERFLOW, если возникает переполнение (попытка повторяется с тем же объектом).

bpf_sk_cgroup_id

u64 bpf_sk_cgroup_id(struct bpf_sock *sk)

Функция возвращает идентификатор cgroup v2 сокета sk. Параметр sk должен быть непустым (не NULL) указателем на полный сокет, например, значением, возвращённым функцией bpf_sk_lookup_tcp(), bpf_sk_lookup_udp(), bpf_sk_fullsock() и т. п. Формат возвращаемого идентификатора совпадает с возвращаемым функцией bpf_skb_cgroup_id().

Эта функция доступна лишь для ядер, собранных с опцией CONFIG_SOCK_CGROUP_DATA.

Функция возвращает найденный идентификатор или 0, если идентификатор извлечь не удалось.

bpf_sk_ancestor_cgroup_id

u64 bpf_sk_ancestor_cgroup_id(struct bpf_sock *sk, int ancestor_level)

Функция возвращает идентификатор cgroup v2, являющийся предком cgroup, связанной с sk на уровне ancestor_level. Корнем cgroup является ancestor_level 0 и каждый шаг вниз по иерархии увеличивает уровень. Если ancestor_level совпадает с уровнем cgroup, связанной с текущей задачей, возвращаемое значение будет совпадать с результатом вызова bpf_sk_cgroup_id().

Функция полезна для реализации правил, основанных на cgroup, которые в иерархии выше cgroup, связанной с sk.

Формат возвращаемого идентификатора и ограничения функции те же, что и для bpf_sk_cgroup_id().

Функция возвращает найденный идентификатор или 0, если идентификатор извлечь не удалось.

bpf_ringbuf_output

long bpf_ringbuf_output(void *ringbuf, void *data, u64 size, u64 flags)

Копирует size байтов и data в кольцевой буфер ringbuf. При наличии BPF_RB_NO_WAKEUP в поле flags, уведомление о доступности новых данных не передаётся, флаг BPF_RB_FORCE_WAKEUP задаёт безусловную передачу такого уведомления.

Функция возвращает 0 при успехе и отрицательный код при ошибке.

bpf_ringbuf_reserve

void *bpf_ringbuf_reserve(void *ringbuf, u64 size, u64 flags)

Резервирует size байтов содержимого (payload) в кольцевом буфере ringbuf.

Возвращает действительный указатель на size байтов доступной памяти или NULL, если выделить память не удалось.

bpf_ringbuf_submit

void bpf_ringbuf_submit(void *data, u64 flags)

Представляет зарезервированную выборку кольцевого буфера, указанную параметром data. При наличии BPF_RB_NO_WAKEUP в поле flags, уведомление о доступности новых данных не передаётся, флаг BPF_RB_FORCE_WAKEUP задаёт безусловную передачу такого уведомления.

Функция всегда успешна и ничего не возвращает.

bpf_ringbuf_discard

void bpf_ringbuf_discard(void *data, u64 flags)

Отбрасывает зарезервированную выборку кольцевого буфера, указанную параметром data. При наличии BPF_RB_NO_WAKEUP в поле flags, уведомление о доступности новых данных не передаётся, флаг BPF_RB_FORCE_WAKEUP задаёт безусловную передачу такого уведомления.

Функция всегда успешна и ничего не возвращает.

bpf_ringbuf_query

u64 bpf_ringbuf_query(void *ringbuf, u64 flags)

Запрашивает характеристики представленного кольцевого буфера, указываемые битами поля flags:

BPF_RB_AVAIL_DATA

объём ещё не потреблённых данных;

BPF_RB_RING_SIZE

размер кольцевого буфера;

BPF_RB_CONS_POS

позиция потребителя (может переходить через «разрыв» кольца);

BPF_RB_PROD_POS

позиция поставщика (может переходить через «разрыв» кольца).

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

Функция возвращает запрошенное значение или 0, если поле flags не распознано.

bpf_csum_level

long bpf_csum_level(struct sk_buff *skb, u64 level)

Меняет уровень контрольной суммы skb на 1 вверх или вниз, или сбрасывает уровень в none, чтобы стек проверил контрольную сумму. Этот уровень применим к протоколам TCP, UDP, GRE, SCTP, FCOE. Например, декапсуляция | ETH | IP | UDP | GUE | IP | TCP | into | ETH | IP | TCP | через функцию bpf_skb_adjust_room() с передачей флага BPF_F_ADJ_ROOM_NO_CSUM_RESET потребует вызова bpf_csum_level() с BPF_CSUM_LEVEL_DEC, поскольку удаляется заголовок UDP. Аналогично, для инкапсуляции обратно может вызываться bpf_csum_level() с BPF_CSUM_LEVEL_INC, если skb всё ещё предназначен для обработки вышележащими уровнями стека, а не просто отправки на выход tc.

В настоящее время поддерживается 3 установки уровня:

BPF_CSUM_LEVEL_INC

повысить skb->csum_level для skb с CHECKSUM_UNNECESSARY;

BPF_CSUM_LEVEL_DEC

понизить skb->csum_level для skb с CHECKSUM_UNNECESSARY;

BPF_CSUM_LEVEL_RESET

сбросить skb->csum_level в 0 и установить CHECKSUM_NONE для проверки контрольной суммы стеком№

BPF_CSUM_LEVEL_QUERY

нет операций, возвращается текущее значение skb->csum_level.

Функция возвращает 0 при успехе и отрицательный код в случае ошибки. При установке BPF_CSUM_LEVEL_QUERY возвращается текущее значение skb->csum_level или код ошибки -EACCES, если для skb не установлено CHECKSUM_UNNECESSARY.

bpf_skc_to_tcp6_sock

struct tcp6_sock *bpf_skc_to_tcp6_sock(void *sk)

Динамически преобразует указатель sk в указатель tcp6_sock.

Функция возвращает sk, если преобразование действительно, и NULL в ином случае.

bpf_skc_to_tcp_sock

struct tcp_sock *bpf_skc_to_tcp_sock(void *sk)

Динамически преобразует указатель sk в указатель tcp_sock.

Функция возвращает sk, если преобразование действительно, и NULL в ином случае.

bpf_skc_to_tcp_timewait_sock

struct tcp_timewait_sock *bpf_skc_to_tcp_timewait_sock(void *sk)

Динамически преобразует указатель sk в указатель tcp_timewait_sock.

Функция возвращает sk, если преобразование действительно, и NULL в ином случае.

bpf_skc_to_tcp_request_sock

struct tcp_request_sock *bpf_skc_to_tcp_request_sock(void *sk)

Динамически преобразует указатель sk в указатель tcp_request_sock.

Функция возвращает sk, если преобразование действительно, и NULL в ином случае.

bpf_skc_to_udp6_sock

struct udp6_sock *bpf_skc_to_udp6_sock(void *sk)

Динамически преобразует указатель sk в указатель udp6_sock.

Функция возвращает sk, если преобразование действительно, и NULL в ином случае.

bpf_get_task_stack

long bpf_get_task_stack(struct task_struct *task, void *buf, u32 size, u64 flags)

Возвращает стек пользователя или ядра в буфере, пердоставленном программой bpf. Для этого функции нужен параметр task, являющийся действительным указателем на структуру task_struct. Для сохранения трассировки стека программа bpf предоставляет буфер buf с неотрицательным размером. Аргумент flags указывает число пропускаемых кадров стека (0 -255) с маской BPF_F_SKIP_FIELD_MASK. Остальные биты могут служить для указанных ниже флагов.

BPF_F_USER_STACK

Работать со стеком пользователя, а не ядра.

BPF_F_USER_BUILD_ID

Собирать buildid+offset вместо ips для пользовательского стека (применимо лишь с флагом BPF_F_USER_STACK).

Функция может собирать да PERF_MAX_STACK_DEPTH кадров из стека пользователя или ядра при наличии достаточно большого буфера. Этим ограничением может управлять программа sysctl и задавать предел вручную для работы с длинным пользовательским стеком (например, в программах Java). Команда установки значения имеет вид

# sysctl kernel.perf_event_max_stack=<new value>

Функция возвращает неотрицательное значение, не превышающее size, при успешном выполнении и отрицательное значение в случае ошибки.

Примеры

Примеры использования большинства функций-помощников eBPF, описанных здесь, доступны в файлах исходного кода ядра Linux, размещённых в каталогах samples/bpf/ и tools/testing/selftests/bpf/.

Реализация

Этот документ является попыткой описать имеющиеся функции-помощники (helper) eBPF. Подсистема BPF активно развивается с добавлением новых программ eBPF, типов отображений, а также функций-помощников. Для проверки наличия функций-помощников в конкретном ядре или получения сведений о поддерживаемых программах следует обращаться к указанным ниже файлам в дереве исходных кодов ядра.

  • include/uapi/linux/bpf.h — основной заголовок BPF, содержащий полный список функций-помощников и другие определения BPF, включая большинство флагов, структур и констант.

  • net/core/filter.c содержит определения большинства относящихся к сети функций-помощников и список типов программ, из которых эти функции можно вызывать.

  • kernel/trace/bpf_trace.c то же, что и предыдущий, но для функций трассировки.

  • kernel/bpf/verifier.c — функции, используемые для проверки использования с данной функцией помощником лишь действительные типы отображений eBPF.

  • Каталог kernel/bpf/ содержит файлы с определениями дополнительных функций-помощников (для cgroup, sockmap и т. п.).

  • Для проверки доступности функций можно использовать утилиту bpftool, например, bpftool feature probe (см. man 8 bpftool-feature). Ключевое слово unprivileged позволяет увидеть функции, доступные непривилегированным пользователям.

Совместимость функций-помощников с разными типами программ обычно описана в файлах с определением функций помощников (объекты struct bpf_func_proto и возвращающие их функции).

Совместимость функций-помощников с типами отображений моно найти в функции check_map_func_compatibility() в файле kernel/bpf/verifier.c.

Функции-помощники, отменяющие результаты проверки указателей data и data_end для сетевой обработки, перечислены в функции bpf_helper_changes_pkt_data() в файле net/core/filter.c.

Литература

[1] Файл Documentation/admin-guide/cgroup-v1/net_cls.rst в дереве исходных кодов ядра Linux.

Перевод на русский язык

Николай Малых

nmalykh@protokols.ru

1Traffic Control — управление трафиком.

2eXpress Data Path — «экспресс-путь» передачи данных.

3Type-Length-Value — тип, размер, значение.

4Non-Uniform Memory Access — неунифицированный доступ к памяти, когда время доступа зависит от расположения памяти относительно процессора.

5Это реализовано пока лишь для естественного XDP (с поддержкой драйвера)

6Performance Monitoring Unit — модуль мониторинга производительности.

7Segment Routing Header — заголовок маршрутизации по сегментам.

8Infrared — инфракрасный.

9Congestion Encountered — наблюдается перегрузка.

10ECN Capable Transport — транспорт с поддержкой ECN.

Рубрика: Linux | Оставить комментарий

RFC 8366 A Voucher Artifact for Bootstrapping Protocols

Internet Engineering Task Force (IETF)                         K. Watsen
Request for Comments: 8366                              Juniper Networks
Category: Standards Track                                  M. Richardson
ISSN: 2070-1721                                       Sandelman Software
                                                             M. Pritikin
                                                           Cisco Systems
                                                               T. Eckert
                                                                  Huawei
                                                                May 2018

A Voucher Artifact for Bootstrapping Protocols

Ваучер для протоколов начальной загрузки

PDF

Аннотация

Этот документ задаёт стратегию защищённого связывания заявителя (pledge) с владельцем с использованием артефакта, напрямую или опосредованного подписанного изготовителем. Этот артефакт называется ваучером (voucher). В документе задан формат ваучера как определённого на языке YANG документа JSON, который подписан с использованием структуры CMS1. Возможны и другие форматы, производные от YANG. Артефакт ваучера обычно создаёт производитель (или уполномоченный производителем орган подписи MASA2). Документ определяет лишь артефакт ваучера, оставляя протоколы доступа к ваучерам другим документам.

Статус документа

Документ относится к категории Internet Standards Track.

Документ является результатом работы IETF3 и представляет согласованный взгляд сообщества IETF. Документ прошёл открытое обсуждение и был одобрен для публикации IESG4. Дополнительную информацию о стандартах Internet можно найти в разделе 2 RFC 7841.

Информацию о текущем статусе документа, ошибках и способах обратной связи можно найти по ссылке https://www.rfc-editor.org/info/rfc8366.

Авторские права

Copyright (c) 2018. Авторские права принадлежат IETF Trust и лицам, указанным в качестве авторов документа. Все права защищены.

К документу применимы права и ограничения, указанные в BCP 78 и IETF Trust Legal Provisions и относящиеся к документам IETF (http://trustee.ietf.org/license-info), на момент публикации данного документа. Прочтите упомянутые документы внимательно. Фрагменты программного кода, включённые в этот документ, распространяются в соответствии с упрощённой лицензией BSD, как указано в параграфе 4.e документа IETF Trust Legal Provisions, без каких-либо гарантий (как указано в Simplified BSD License).

1. Введение

Этот документ задаёт стратегию защищённого связывания устройства-кандидата (заявителя) с владельцем с помощью артефакта, подписанного напрямую или опосредованно изготовителем (уполномоченным этим производителем агнетом MASA). Этот артефакт называется ваучером.

Артефакт ваучера является документом JSON [RFC8259], соответствующим модели данных YANG [RFC7950], закодированным по правилам [RFC8259] и подписанным с использованием (по умолчанию) структуры CMS [RFC5652].

Основным назначением ваучера является защищённый перенос сертификата pinned-domain-cert, который заявитель может использовать для аутентификации последующих взаимодействий. Ваучер может быть полезен в разных случаях, но основным здесь является поддержка защищённых механизмов начальной загрузки. Назначение владения важно для механизмов начальной загрузки, чтобы заявитель мог аутентифицировать сеть, которая пытается получить контроль над ним.

Срок действия ваучером может меняться. В некоторых протоколах начальной загрузки ваучеры могут включать одноразовые значения (nonce), тогда как другие протоколы могут явно задавать срок действия. Для поддержки длительных сроков действия этот документ рекомендует использовать краткосрочные ваучера с механизмом программного обновления (параграф 6.1. Обновление вместо отзыва).

Этот документ задаёт лишь артефакт ваучера, оставляя другим документам описание протоколов для работы с ваучерами. Протоколы для работы с определенным здесь артефактом ваучера включают [ZERO-TOUCH], [SECUREJOIN], [KEYINFRA].

2. Терминология

Artifact — артефакт

Здесь представляет ваучер как созданный экземпляр в форме подписанной структуры.

Domain — домен

Набор сущностей (объектов) или инфраструктура с единым административным управлением. Целью протокола начальной загрузки является обнаружением заявителем домена и присоединение к нему.

Imprint — принятие отпечатка

Процесс, где устройство получает криптографический ключевой материал для отождествления и доверия к будущим взаимодействиям с сетью. Этот термин взят из работы Конрада Лоренца (Konrad Lorenz) по биологии утят: «в критический период утёнок будет предполагать, что все, похожее на утку-мать, фактически является его матерью» [Stajano99theresurrecting]. Эквивалентом для устройства является получения отпечатка (fingerprint) сертификата корневого удостоверяющего центра сети. Устройство, принявшее отпечаток от злоумышленника, постигнет судьба, похожая на судьбу утёнка, принявшего волка за мать. Термин imprinting применяется в психологии и этологии [imprinting].

Join Registrar (Coordinator) — регистратор присоединения (координатор)

Представитель домена, настроенный (возможно, автономно) для принятия решений о присоединении новых устройств к домену. Администратор домена взаимодействует с регистратором присоединения (и координатором) для управления этим процессом. Обычно регистратор размещается «внутри» домена. Для простоты в документе используется просто «регистратор».

MASA (Manufacturer Authorized Signing Authority) — уполномоченный изготовителем агент подписи

сущность, которая (для целей этого документа) подписывает ваучеры для продукции изготовителя (заявителей). В некоторых протоколах начальной загрузки MASA может присутствовать в Internet и быть частью процесса начальной загрузки, а в других протоколах MASA является автономной службой, которая не играет активной роли в процессе начальной загрузки.

Owner — владелец

Сущность, управляющая секретным ключом сертификата pinned-domain-cert, содержащегося в ваучере.

Pledge — заявитель

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

Registrar — регистратор

См. join registrar.

TOFU (Trust on First Use) — доверие при первом использовании

Когда устройство-заявитель не принимает решений о защите, а просто доверяет первой сущности из домена, с которым оно соединяется. Термин применяется как в [RFC7435]. Называется также моделью воскресающего утёнка (resurrecting duckling).

Voucher — ваучер

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

3. Уровни требований

Ключевые слова необходимо (MUST), недопустимо (MUST NOT), требуется (REQUIRED), нужно (SHALL), не следует (SHALL NOT), следует (SHOULD), не нужно (SHOULD NOT), рекомендуется (RECOMMENDED), не рекомендуется (NOT RECOMMENDED), возможно (MAY), необязательно (OPTIONAL) в данном документе интерпретируются в соответствии с BCP 14 [RFC2119] [RFC8174] тогда и только тогда, когда они выделены шрифтом, как показано здесь.

4. Типы ваучеров

Ваучер является криптографически защищённым заявлением для устройства, разрешающим бесконтактный (zero-touch) отпечаток (imprint) для регистратора домена. Конкретные сведения, предоставляемые ваучером, зависят от применяемого варианта начальной загрузки. Ваучер может сообщать регистратору присоединения и заявителю указанные ниже сведения.

Assertion Basis — основы контроля

Указывает метод защиты отпечатка (отличается от подписи ваучера, которая защищает сам ваучер). Это может включать подтверждённую изготовителем проверку владения, обеспеченные операции ведения журнала или зависимость от поведения конечной точки заявителя, такого как защищённый корень доверия для измерений. Этот документ нормативно задаёт лишь некоторые методы, оставляя другие будущим работам.

Authentication of Join Registrar — аутентификация регистратора

Указывает способ проверки заявителем подлинности регистратора. Этот документ задаёт механизм закрепления сертификата домена. Закрепление симметричного, необработанного (raw) ключа, данных CN-ID или DNS-ID (как задано в [RFC6125]) оставлено для будущих работ.

Anti-Replay Protections — защита от повторов

Сведения на основе времени или одноразового значения nonce для ограничения срока действия ваучера или числа попыток начальной загрузки.

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

Assertion

Registrar ID

Validity

Тип ваучера

Logged

Verified

Trust Anchor

CN-ID или DNS-ID

RTC

Nonce

Audit — аудит

X

X

X

Nonceless Audit — аудит без Nonce

X

X

X

Owner Audit — аудит владельца

X

X

X

X

X

Owner ID — идентификатор владельца

X

X

X

X

Bearer out-of-scope — носитель вне области действия

X

шаблон

необязательно

Примечание. Все типы ваучеров включают pledge ID serial-number (не показан для экономии места).

Audit Voucher — ваучер аудита

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

Nonceless Audit Voucher — ваучер аудита без Nonce

Ваучер аудита без проверки срока действия. Отличается от обычного Audit Voucher тем, что его можно выпускать заранее для поддержки разделения сети или обеспечения удалённого развертывания.

Ownership Audit Voucher — ваучер аудита владения

Ваучер аудита с подтверждением службой MASA того, что регистратор является полномочным владельцем. Служба MASA смягчает действия MiTM-регистраторов, отвергая создание Audit Voucher для несанкционированных регистраторов. Регистратор применяет аудит в дополнение к MASA. Это обеспечивает идеальный вариант совместного принятия решений и применения правил производителем и владельцем.

Ownership ID Voucher — ваучер идентификатора владения

Ваучер с включением идентификатора CN-ID или DNS-ID. Служба MASA смягчает действия MiTM-регистраторов, идентифицируя конкретного регистратора (через WebPKI), уполномоченного владеть заявителем.

Bearer Voucher — ваучер носителя

Ваучер с включением шаблона идентификатора регистратора. Поскольку идентификатор регистратора не указан, этот тип ваучера должен считаться секретным и требующим защиты от раскрытия, поскольку любой «носитель» ваучера может указать владение заявителем. Публикация ваучера носителя без nonce фактически превращает указанного заявителя в устройство TOFU с минимальным смягчением действий MiTM-регистраторов. Этот тип ваучеров не рассматривается в документе.

5. Артефакт ваучера

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

Этот документ задаёт ваучер, являющийся документом JSON, представляющим экземпляр модуля YANG, определённого в параграфе 5.3, который по умолчанию имеет подпись CMS. Формат описан здесь как практическая основа для некоторых применений (таких как NETCONF), но больше для чёткой демонстрации того, как ваучеры выглядят на практике. Описание служит также для утверждения (validate) модели данных YANG.

Предполагается определение в будущих работах новых отображений ваучеров с кратким представлением двоичных объектов (Concise Binary Object Representation или CBOR) из JSON и замена контейнера подписи CMS на JOSE6 или COSE7. Допустимы также форматы XML и ASN.1.

Этот документ задаёт тип носителя (media type) и расширение имён файлов для типа JSON с кодированием CMS. В будущих документах для других форматов будут заданы дополнительные типы носителей. Сигнализация осуществляется в форме MIME Content-Type заголовка HTTP Accept или более простых методов, таких как использование расширений имён файлов при передаче ваучеров на устройствах USB.

5.1. Диаграмма дерева

Ниже представлено верхний уровень дерева документа с ваучером на основе нотации [RFC8340]. Каждый узел дерева полностью описан в модуле YANG, заданном в параграфе 5.3. Модуль YANG.

   module: ietf-voucher

     yang-data voucher-artifact:
         +---- voucher
            +---- created-on                       yang:date-and-time
            +---- expires-on?                      yang:date-and-time
            +---- assertion                        enumeration
            +---- serial-number                    string
            +---- idevid-issuer?                   binary
            +---- pinned-domain-cert               binary
            +---- domain-cert-revocation-checks?   boolean
            +---- nonce?                           binary
            +---- last-renewal-date?               yang:date-and-time

5.2. Примеры

Этот параграф содержит иллюстративные примеры ваучеров с кодированием по правилам [RFC8259].

Ниже приведён пример эфемерного ваучера (с использованием nonce). MASA генерирует такой ваучер с использованием типа утверждения logged, зная, что это подходит для подающего запрос заявителя.

   {
     "ietf-voucher:voucher": {
       "created-on": "2016-10-07T19:31:42Z",
       "assertion": "logged",
       "serial-number": "JADA123456789",
       "idevid-issuer": "base64encodedvalue==",
       "pinned-domain-cert": "base64encodedvalue==",
       "nonce": "base64encodedvalue=="
     }
   }

Ниже приведён пример неэфемерного ваучера (без nonce). Хотя срок действия этого ваучера истекает через две недели, его, предположительно, можно продлить на срок до года. MASA генерирует такой ваучер с использованием типа утверждения verified, который должен подходить для всех заявителей.

   {
     "ietf-voucher:voucher": {
       "created-on": "2016-10-07T19:31:42Z",
       "expires-on": "2016-10-21T19:31:42Z",
       "assertion": "verified",
       "serial-number": "JADA123456789",
       "idevid-issuer": "base64encodedvalue==",
       "pinned-domain-cert": "base64encodedvalue==",
       "domain-cert-revocation-checks": true,
       "last-renewal-date": "2017-10-07T19:31:42Z"
     }
   }

5.3. Модуль YANG

Приведённый ниже модуль YANG [RFC7950] формально описывает структуру ваучера в форме документа JSON.

<CODE BEGINS> file "ietf-voucher@2018-05-09.yang"
module ietf-voucher {
  yang-version 1.1;
  namespace "urn:ietf:params:xml:ns:yang:ietf-voucher";
  prefix vch;

  import ietf-yang-types {
    prefix yang;
    reference "RFC 6991: Common YANG Data Types";
  }
  import ietf-restconf {
    prefix rc;
    description
      "Этот оператор импорта присутствует лишь для доступа к
       расширению yang-data, определённому в RFC 8040.";
    reference "RFC 8040: RESTCONF Protocol";
  }

  organization
    "IETF ANIMA Working Group";
  contact
    "WG Web:   <https://datatracker.ietf.org/wg/anima/> 
     WG List:  <mailto:anima@ietf.org> 
     Author:   Kent Watsen
               <mailto:kwatsen@juniper.net> 
     Author:   Max Pritikin
               <mailto:pritikin@cisco.com> 
     Author:   Michael Richardson
               <mailto:mcr+ietf@sandelman.ca> 
     Author:   Toerless Eckert
               <mailto:tte+ietf@cs.fau.de>"; 
  description
    "Модуль задаёт формат для ваучера, который создаётся изготовителем
     устройства-заявителя или делегируется агенту MASA для защищённого 
     связывания заявителя с владельцем, чтобы заявитель мог организовать
     защищённое соединение с сетевой инфраструктурой владельца.

     Ключевые слова ДОЛЖНО, НЕДОПУСТИМО, ТРЕБУЕТСЯ, НУЖНО, НЕ НУЖНО, 
     СЛЕДУЕТ, НЕ СЛЕДУЕТ, РЕКОМЕНДУЕТСЯ, НЕ РЕКОМЕНДУЕТСЯ, МОЖНО,
     НЕОБЯЗАТЕЛЬНО в этом документе трактуются в соответствии с 
     BCP 14 (RFC 2119) (RFC 8174) тогда и только тогда, когда они
     указаны заглавными буквами, как показано здесь.

     Авторские права (Copyright (c) 2018) принадлежат IETF Trust и
     лицам, указанным как авторы. Все права защищены.

     Распространение и применение модуля в исходной или двоичной 
     форме с изменениями или без таковых разрешено в соответствии с
     лицензией Simplified BSD License, изложенной в параграфе 4.c
     IETF Trust's Legal Provisions Relating to IETF Documents
     (https://trustee.ietf.org/license-info). 

     Эта версия модуля YANG является частью RFC 8366, где правовые
     аспекты приведены более полно.";

  revision 2018-05-09 {
    description
      "Исходный выпуск";
    reference "RFC 8366: Voucher Profile for Bootstrapping Protocols";
  }

  // Оператор верхнего уровня
  rc:yang-data voucher-artifact {
    uses voucher-artifact-grouping;
  }

  // Группировка, определённая для будущих дополнений

  grouping voucher-artifact-grouping {
    description
      "Группировка для использования и расширения в будущем.";
    container voucher {
      description
        "Ваучер связывает заявителя с владельцем(pinned-domain-cert).";
      leaf created-on {
        type yang:date-and-time;
        mandatory true;
        description
          "Дата создания ваучера. Этот узел предназначен, прежде всего, 
           для человека и систем аудита. В будущем на основе этого узла
           МОГУТ задаваться требования к проверке.";
      }
      leaf expires-on {
        type yang:date-and-time;
        must 'not(../nonce)';
        description
          "Срок действия ваучера. Узел необязателен и не все заявители
           поддерживают ограничение срока (например, при отсутствии 
           надёжных часов).

           При наличии этого поля заявители ДОЛЖНЫ гарантировать, что 
           указанное время ещё не наступило. Заявители без точных часов
           не соответствуют этому требованию.

           В expires-on НЕДОПУСТИМО указывать время после истечения
           срока действия любого из сертификатов в pinned-domain-cert.";
      }
      leaf assertion {
        type enumeration {
          enum verified {
            description
              "Указывает позитивный результат проверки владения агентом
               MASA (например, через канал продаж).";
          }
          enum logged {
            description
              "Указывает, что ваучер был выпущен после минимальной
               проверки прав владения или управления. Выпуск был записан
               в журнал для обнаружения возможных проблем безопасности
               (например, получатели ваучеров могут убедиться сами, что 
               в журнале нет неожиданных ваучеров). Это похоже на 
               незащищённое доверие при первом использовании (TOFU), но 
               с ведением журнала для обнаружения неожиданных событий.";
          }
          enum proximity {
            description
              "Указывает, что ваучер был выпущен после проверки агентом
               MASA подтверждения близости, представленного устройством
               и целевым доменом. Выпуск был записан в журнал для 
               обнаружения возможных проблем безопасности. Это сильнее,
               чем просто запись в журнал, поскольку требует проверки
               взаимодействия заявителя и владельца, но все равно 
               зависит от анализа журнала для обнаружения неожиданных
               событий.";
          }
        }
        mandatory true;
        description
          "Утверждение (assertion) - это заявление MASA о способе
           проверки владельца. Это позволяет заявителю более подробно
           проверить правила. Заявители ДОЛЖНЫ гарантировать пригодность
           утверждения в соответствии с локальными правилами до 
           начала обработки ваучера.";
      }
      leaf serial-number {
        type string;
        mandatory true;
        description
          "Порядковый номер оборудования. При обработке ваучера 
           заявитель ДОЛЖЕН подтвердить соответствие своего порядкового
           номера этому значению. При несовпадении заявителю НЕДОПУСТИМО
           обрабатывать этот ваучер.";
      }
      leaf idevid-issuer {
        type binary;
        description
          "СТРОКА ОКТЕТОВ идентификатора ключа агентства (Authority 
           Key Identifier), определённого в параграфе 4.2.1.1 RFC 5280,
           из сертификата IDevID заявителя. Лист необязателен,
           поскольку некоторые порядковые номера уже уникальны в
           сфере действия MASA. Включение статистически уникального
           идентификатора ключа обеспечивает статистически уникальную
           идентификацию оборудования. При обработке ваучера заявитель
           ДОЛЖЕН гарантировать соответствие IDevID Authority Key
           этому значению. При несовпадении обработка ваучера
           НЕДОПУСТИМА.

           При выпуске ваучера агент MASA ДОЛЖЕН обеспечить в этом поле
           порядковый номер, который в остальном неуникален в рамках
           действия MASA.";
      }
      leaf pinned-domain-cert {
        type binary;
        mandatory true;
        description
          "Структура сертификата X.509 v3, заданная RFC 5280, с 
           кодированием DER (Distinguished Encoding Rules) в 
           соответствии с ITU-T X.690.

           Этот сертификат используется заявителем для доверия к 
           инфраструктуре открытых ключей (Public Key Infrastructure)
           для проверки сертификата домена, представленного заявителю
           независимо протоколом начальной загрузки. Сертификат домена
           ДОЛЖЕН включать этот сертификат в свою цепочку сертификации.
           Это МОЖЕТ быть сертификат конечного объекта, в том числе
           самоподписанный.";
        reference
          "RFC 5280:
             Internet X.509 Public Key Infrastructure Certificate
             and Certificate Revocation List (CRL) Profile.
           ITU-T X.690:
              Information technology - ASN.1 encoding rules:
              Specification of Basic Encoding Rules (BER),
              Canonical Encoding Rules (CER) and Distinguished
              Encoding Rules (DER).";
      }
      leaf domain-cert-revocation-checks {
        type boolean;
        description
          "Указание заявителю, что он ДОЛЖЕН (true) или ему НЕДОПУСТИМО
           (false) проверять статус отзыва для прикреплённого доменного
           сертификата. Если это поле не задано, используется обычное
           поведение PKIX для проверки сертификата домена.";
      }
      leaf nonce {
        type binary {
          length "8..32";
        }
        must 'not(../expires-on)';
        description
          "Значение, которое заявитель может применять в некоторых
           протоколах начальной загрузки для предотвращения повторов
           (anti-replay). Узел необязателен, поскольку его применяют
           не все протоколы начальной загрузки.

           При наличии листа заявитель ДОЛЖЕН сравнить представленное
           значение nonce с другим значением, которое случайно создано
           заявителем и передано серверу начальной загрузки в начальном
           сообщении. При несовпадении заявителю НЕДОПУСТИМО 
           обрабатывать этот ваучер.";
      }
      leaf last-renewal-date {
        type yang:date-and-time;
        must '../expires-on';
        description
          "Финальная дата возможности продления ваучера с точки зрения 
           MASA. Информативное поле, не обрабатываемое заявителем.

           После создания ваучера могут возникнуть обстоятельства, 
           меняющие срок его действия. Например, производитель может 
           связывать срок действия с контрактами на поддержку, которые 
           могут продлеваться и расторгаться.";
      }
    } // end voucher
  } // end voucher-grouping
}
<CODE ENDS>

5.4. Формат CMS для артефакта ваучера

Развитием PKCS#7 в IETF является CMS [RFC5652]. Подписанный CMS ваучер, как принято по умолчанию, включает структуру ContentInfo с содержимым ваучера. Тип eContentType 40 указывает, что содержимое является ваучером в кодировке JSON.

Подпись является структурой CMS SignedData, как указано в параграфе 5.1 [RFC5652], закодированной в соответствии с ASN.1 DER8, как указано в ITU-T X.690 [ITU.X690.2015].

Для улучшения совместимости параграф 8.3 в этом документе регистрирует тип носителя application/voucher-cms+json и расширение имён файлов .vcj.

Структура CMS должна включать структуру signerInfo, описанную в параграфе 5.1 [RFC5652], с подписью содержимого, использующей секретный ключ, которому доверяет получатель. Обычно получателем является заявитель, а подписывающей стороной — MASA. Другим возможным вариантом является формат подписанного запроса ваучера от заявителя или регистратора к агенту MASA. В этом документе подписывающей стороной считается MASA.

Отметим, что в параграфе 5.1 [RFC5652] рассматривается проверка объекта CMS, который на деле является объектом PKCS7 (cmsVersion=1). Промежуточные системы, такие как регистраторы инфраструктуры удалённых защищённых ключей начальной загрузки (Bootstrapping Remote Secure Key Infrastructures или BRSKI), которым может потребоваться оценка вайчера «на лету», должны быть готовы к этому устаревшему формату. Сигнализация не требуется, поскольку изготовителю известны возможности заявителя и он будет применять для каждого заявителя нужный формат.

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

Структура CMS может также включать объекты отзыва для любых промежуточных удостоверяющих центров (certificate authority или CA) между эмитентом ваучера и известной получателю привязкой доверия. Однако применение CRL и других механизмов проверки не рекомендуется, поскольку маловероятна способность заявителя выполнить online-проверку и наличие у него доверенного источника времени. Как описано ниже, использование краткосрочных ваучеров и/или представленное заявителем значение nonce обеспечивает гарантию актуальности ваучера.

6. Соображения по устройству

6.1. Обновление вместо отзыва

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

Артефакты отзыва обычно применяются для проверки действительности утверждений, таких как сертификаты PKIX, web-маркеры, «ваучеры». При таком подходе потенциально долгосрочные утверждения сочетаются с частой проверкой статуса отзыва, чтобы убедиться в фактической действительности утверждений. Однако это усложняет решения, поскольку требует дополнительных протоколов и кода для распространения и обработки отзывов.

Для устранения недостатков аннулирования этот документ рекомендует применять упрощённое продление краткосрочных безотзывных ваучеров. Вместо выпуска долгосрочного ваучера, где лист expires-on указывает далёкое будущее, предполагается, что агент MASA выдаёт краткосрочные ваучеры, где лист expires-on указывает сравнительно близкое время вместе с обещанием (поле last-renewal-date) при необходимости повторно выдать ваучер. Важно подчеркнуть, что, несмотря на серьёзные проверки при первом выпуске ваучера (Вы тот, за кого себя выдаёте? Заявитель действительно принадлежит вам?), повторный выпуск ваучеров следует упрощать, поскольку он, вероятно, лишь обновляет срок действия ваучера. При таком подходе имеется лишь один артефакт, и нужен лишь один путь кода — у заявителя нет возможности пропустить проверку статуса отзыва ваучера, например, по причине недоступности ответчика OCSP.

Хотя этот документ рекомендует краткосрочные ваучеры, артефакт ваучера не препятствует созданию долгосрочных, однако метод отзыва в документе не описан.

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

6.2. Ваучер на одного заявителя

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

7. Вопросы безопасности

7.1. Точность часов

Злоумышленник может использовать просроченный ваучер для получения контроля над устройством, которое не понимает времени (не имеет часов). Устройство не может доверять NTP как эталону времени, поскольку атакующий может контролировать поток NTP.

Имеется три варианта защиты: 1) устройство должны убедиться, что время ещё не достигло значения, указанного в поле expires-on, 2) устройство без доступа к часам может применять nonce для получения эфемерных ваучеров, 3) могут применяться ваучеры с неограниченным сроком действия, которые будут включаться в журнал аудита, информируя о защитном решении.

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

7.2. Защита ваучера с помощью HSM

В соответствии с рекомендациями параграфа 6.1. Обновление вместо отзыва для MASA в качестве службы подписи ваучеров рекомендуется защищать секретный ключ MASA, применяемый для подписи ваучеров, защищать с помощью аппаратного модуля (hardware security module или HSM).

7.3. Проверка сертификата домена при подписи

Если сертификат домена скомпрометирован, злоумышленник может воспользоваться остающимися ваучерами этого домена. Очевидно, что администратор домена должен инициировать отзыв любых сертификатов отождествления домена (как в обычных решениях PKI). Предполагается также контакт с MASA, чтобы указать необходимость блокировки обновления остающихся ваучеров (предположительно, краткосрочных). Протоколам распространения ваучеров рекомендуется проверять отзыв сертификатов отождествления домена до подписания ваучеров.

7.4. Вопросы безопасности модуля YANG

Заданный здесь модуль YANG определяет схему для данных, которые инкапсулируются в тип носителя с подписью CMS, как описано в разделе 5 [RFC5652]. Таким образом смоделированные в YANG данные будут защищены от изменения.

Реализациям следует помнить, что подписанные данные лишь защищены от внешнего изменения, но остаются видимыми. Возможное раскрытие информации влияет не только на безопасность, но и на приватность. В частности, злоумышленники могут собирать такие сведения, как принадлежность устройств организации, точки распространения списков отзыва (CRL Distribution Point) и ссылки на ответчики OCSP (OCSP Responder URL), применяемые для проверки ваучеров. Когда сохранение приватности важно, данные с подписью CMS следует защищать путём передачи через защищённый транспорт с взаимной аутентификацией (например, TLS [RFC5246]) или инкапсуляции в тип enveloped-data (раздел 6 в [RFC5652]), но детали этого выходят за рамки документа.

Использование YANG для задания структур данных с помощью оператора yang-data является сравнительно новым и отличается от традиционного применения YANG для определения API с доступом по протоколам управления сетью, таким как NETCONF [RFC6241] и RESTCONF [RFC8040]. Поэтому приведённые здесь рекомендации не соответствуют шаблону, заданному в параграфе 3.7 [YANG-GUIDE].

8. Взаимодействие с IANA

8.1. Реестр IETF XML

Этот документ регистрирует URI в реестре IETF XML Registry [RFC3688]

      URI: urn:ietf:params:xml:ns:yang:ietf-voucher
      Registrant Contact: The ANIMA WG of the IETF.
      XML: N/A, запрошенный URI является пространством имён XML.

8.2. Реестр YANG Module Names

Этот документ регистрирует модуль YANG в реестре YANG Module Names [RFC6020]

      name:         ietf-voucher
      namespace:    urn:ietf:params:xml:ns:yang:ietf-voucher
      prefix:       vch
      reference:    RFC 8366

8.3. Реестр Media Types

Этот документ регистрирует новый тип носителя в реестре Media Types [RFC6838]

   Type name:  application
   Subtype name:  voucher-cms+json
   Required parameters:  нет
   Optional parameters:  нет
   Encoding considerations: ваучеры JSON с подписью CMS и кодированием ASN.1/DER.
   Security considerations: см. раздел 7
   Interoperability considerations: формат предназначен для широкой совместимости.
   Published specification:  RFC 8366
   Applications that use this media type: системы автоматических «отпечатков» ANIMA, 6tisch, NETCONF.
   Fragment identifier considerations:  нет
   Additional information:
      Deprecated alias names for this type:  нет
      Magic number(s):  нет
      File extension(s):  .vcj
      Macintosh file type code(s):  нет
   Person and email address to contact for further information:
      IETF ANIMA WG
   Intended usage:  LIMITED
   Restrictions on usage:  нет
   Author:  ANIMA WG
   Change controller:  IETF
   Provisional registration? (standards tree only):  нет

8.4. Реестр SMI Security for S/MIME CMS Content Type

Агентство IANA зарегистрировало идентификатор OID в реестре SMI Security for S/MIME CMS Content Type (1.2.840.113549.1.9.16.1).

 

Десятичное значение

Описание

Документ

40

id-ct-animaJSONVoucher

RFC 8366

 

9. Литература

9.1. Нормативные документы

[ITU.X690.2015] International Telecommunication Union, «Information Technology — ASN.1 encoding rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished Encoding Rules (DER)», ITU-T Recommendation X.690, ISO/IEC 8825-1, August 2015, <https://www.itu.int/rec/T-REC-X.690/>.

[RFC2119] Bradner, S., «Key words for use in RFCs to Indicate Requirement Levels», BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, <https://www.rfc-editor.org/info/rfc2119>.

[RFC5652] Housley, R., «Cryptographic Message Syntax (CMS)», STD 70, RFC 5652, DOI 10.17487/RFC5652, September 2009, <https://www.rfc-editor.org/info/rfc5652>.

[RFC6020] Bjorklund, M., Ed., «YANG — A Data Modeling Language for the Network Configuration Protocol (NETCONF)», RFC 6020, DOI 10.17487/RFC6020, October 2010, <https://www.rfc-editor.org/info/rfc6020>.

[RFC7950] Bjorklund, M., Ed., «The YANG 1.1 Data Modeling Language», RFC 7950, DOI 10.17487/RFC7950, August 2016, <https://www.rfc-editor.org/info/rfc7950>.

[RFC8174] Leiba, B., «Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words», BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017, <https://www.rfc-editor.org/info/rfc8174>.

[RFC8259] Bray, T., Ed., «The JavaScript Object Notation (JSON) Data Interchange Format», STD 90, RFC 8259, DOI 10.17487/RFC8259, December 2017, <https://www.rfc-editor.org/info/rfc8259>.

9.2. Дополнительная литература

[imprinting] Wikipedia, «Wikipedia article: Imprinting», February 2018, <https://en.wikipedia.org/w/index.php?title=Imprinting_(psychology)&oldid=825757556>.

[KEYINFRA] Pritikin, M., Richardson, M., Behringer, M., Bjarnason, S., and K. Watsen, «Bootstrapping Remote Secure Key Infrastructures (BRSKI)», Work in Progress9, draft-ietf-anima-bootstrapping-keyinfra-12, March 2018.

[RFC3688] Mealling, M., «The IETF XML Registry», BCP 81, RFC 3688, DOI 10.17487/RFC3688, January 2004, <https://www.rfc-editor.org/info/rfc3688>.

[RFC5246] Dierks, T. and E. Rescorla, «The Transport Layer Security (TLS) Protocol Version 1.2», RFC 5246, DOI 10.17487/RFC5246, August 2008, <https://www.rfc-editor.org/info/rfc5246>.

[RFC6125] Saint-Andre, P. and J. Hodges, «Representation and Verification of Domain-Based Application Service Identity within Internet Public Key Infrastructure ping X.509 (PKIX) Certificates in the Context of Transport Layer Security (TLS)», RFC 6125, DOI 10.17487/RFC6125, March 2011, <https://www.rfc-editor.org/info/rfc6125>.

[RFC6241] Enns, R., Ed., Bjorklund, M., Ed., Schoenwaelder, J., Ed., and A. Bierman, Ed., «Network Configuration Protocol (NETCONF)», RFC 6241, DOI 10.17487/RFC6241, June 2011, <https://www.rfc-editor.org/info/rfc6241>.

[RFC6838] Freed, N., Klensin, J., and T. Hansen, «Media Type Specifications and Registration Procedures», BCP 13, RFC 6838, DOI 10.17487/RFC6838, January 2013, <https://www.rfc-editor.org/info/rfc6838>.

[RFC7435] Dukhovni, V., «Opportunistic Security: Some Protection Most of the Time», RFC 7435, DOI 10.17487/RFC7435, December 2014, <https://www.rfc-editor.org/info/rfc7435>.

[RFC8040] Bierman, A., Bjorklund, M., and K. Watsen, «RESTCONF Protocol», RFC 8040, DOI 10.17487/RFC8040, January 2017, <https://www.rfc-editor.org/info/rfc8040>.

[RFC8340] Bjorklund, M. and L. Berger, Ed., «YANG Tree Diagrams», BCP 215, RFC 8340, DOI 10.17487/RFC8340, March 2018, <https://www.rfc-editor.org/info/rfc8340>.

[SECUREJOIN] Richardson, M., «6tisch Secure Join protocol», Work in Progress, draft-ietf-6tisch-dtsecurity-secure-join-01, February 2017.

[Stajano99theresurrecting] Stajano, F. and R. Anderson, «The Resurrecting Duckling: Security Issues for Ad-Hoc Wireless Networks», 1999, <https://www.cl.cam.ac.uk/research/dtg/www/files/publications/public/files/tr.1999.2.pdf>.

[YANG-GUIDE] Bierman, A., «Guidelines for Authors and Reviewers of YANG Data Model Documents», Work in Progress10, draft-ietf-netmod-rfc6087bis-20, March 2018.

[ZERO-TOUCH] Watsen, K., Abrahamsson, M., and I. Farrer, «Zero Touch Provisioning for Networking Devices», Work in Progress11, draft-ietf-netconf-zerotouch-21, March 2018.

Благодарности

Авторы благодарны за обсуждение William Atwood, Toerless Eckert, Sheng Jiang (по фамилиям в алфавитном порядке).

Russ Housley представил обновление PKCS7 на CMS (RFC 5652) вместе с детальной структурой CMS.

Адреса авторов

Kent Watsen
Juniper Networks
Email: kwatsen@juniper.net
 
Michael C. Richardson
Sandelman Software
Email: mcr+ietf@sandelman.ca
URI: http://www.sandelman.ca/
 
Max Pritikin
Cisco Systems
Email: pritikin@cisco.com
 
Toerless Eckert
Huawei USA — Futurewei Technologies Inc.
2330 Central Expy
Santa Clara 95050
United States of America
Email: tte+ietf@cs.fau.de, toerless.eckert@huawei.com

Перевод на русский язык

Николай Малых

nmalykh@protokols.ru

1Cryptographic Message Syntax — синтаксис криптографических сообщений.

2Manufacturer Authorized Signing Authority.

3Internet Engineering Task Force — комиссия по решению инженерных задач Internet.

4Internet Engineering Steering Group — комиссия по инженерным разработкам Internet.

5Man-in-The-Middle — перехват и изменение данных с участием человека.

6JSON Object Signing and Encryption — подписание и шифрование объектов JSON.

7CBOR Object Signing and Encryption — подписание и шифрование объектов CBOR.

8Distinguished Encoding Rules — правила отличительного кодирования.

9Опубликовано в RFC 8995. Прим. перев.

10Опубликовано в RFC 8407. Прим. перев.

11Опубликовано в RFC 8572. Прим. перев.

Рубрика: RFC | Оставить комментарий

RFC 8342 Network Management Datastore Architecture (NMDA)

Internet Engineering Task Force (IETF)                      M. Bjorklund
Request for Comments: 8342                                Tail-f Systems
Updates: 7950                                           J. Schoenwaelder
Category: Standards Track                              Jacobs University
ISSN: 2070-1721                                                P. Shafer
                                                               K. Watsen
                                                        Juniper Networks
                                                               R. Wilton
                                                           Cisco Systems
                                                              March 2018

Архитектура хранилища данных сетевого управления NMDA

Network Management Datastore Architecture (NMDA)

PDF

Аннотация

Хранилища данных являются фундаментальной концепцией привязки моделей данных, написанных на языке моделирования YANG, к протоколам сетевого управления, таким как NETCONF1 и RESTCONF. Этот документ определяет архитектурную модель для хранилищ данных на основе опыта, полученного с начальными простыми моделями, которая решает вопросы, не поддерживаемые первоначальной моделью. Документ обновляет RFC 7950.

Статус документа

Документ относится к категории Internet Standards Track.

Документ является результатом работы IETF2 и представляет согласованный взгляд сообщества IETF. Документ прошёл открытое обсуждение и был одобрен для публикации IESG3. Не все одобренные IESG документы претендуют на статус Internet Standard (см. раздел 2 в RFC 7841).

Информацию о текущем статусе документа, ошибках и способах обратной связи можно найти по ссылке https://www.rfc-editor.org/info/rfc8342.

Авторские права

Авторские права (Copyright (c) 2018) принадлежат IETF Trust и лицам, указанным в качестве авторов документа. Все права защищены.

К документу применимы права и ограничения, указанные в BCP 78 и IETF Trust Legal Provisions и относящиеся к документам IETF (http://trustee.ietf.org/license-info), на момент публикации данного документа. Прочтите упомянутые документы внимательно. Фрагменты программного кода, включённые в этот документ, распространяются в соответствии с упрощённой лицензией BSD, как указано в параграфе 4.e документа IETF Trust Legal Provisions, без каких-либо гарантий (как указано в Simplified BSD License).

1. Введение

Этот документ предоставляет архитектурную модель для хранилищ данных, используемых протоколами сетевого управления типа NETCONF [RFC6241] и RESTCONF [RFC8040], а также языком моделирования данных YANG [RFC7950]. Хранилища являются фундаментальной концепцией, привязывающей модели данных сетевого управления к протоколам сетевого управления. Согласование общей архитектурной модели хранилища данных позволит создавать модели данных без привязки к конкретному протоколу сетевого управления. Эта архитектурная основа идентифицирует набор концептуальных хранилищ, но не обязывает все протоколы сетевого управления предоставлять все эти концептуальные хранилища. Архитектура не привязана к кодированию, используемому протоколами сетевого управления.

Данный документ обновляет RFC 7950 в части определения доступного дерева для некоторых вариантов контекста XPath4 (см. параграф 6.1) и контекста вызова операций ( см. параграф 6.2).

Ключевые слова необходимо (MUST), недопустимо (MUST NOT), требуется (REQUIRED), нужно (SHALL), не следует (SHALL NOT), следует (SHOULD), не нужно (SHOULD NOT), рекомендуется (RECOMMENDED), не рекомендуется (NOT RECOMMENDED), возможно (MAY), необязательно (OPTIONAL) в данном документе интерпретируются в соответствии с BCP 14 [RFC2119] [RFC8174] тогда и только тогда, когда они выделены шрифтом, как показано здесь.

2. Цели

Объекты данных сетевого управления зачастую могут иметь два значения — одно значение задано пользователем или приложением (конфигурация), а второе используется устройством в настоящий момент (текущее состояние). Эти два значения по многим причинам (например, внутреннее взаимодействие системы с оборудованием, взаимодействие с протоколами и другими устройствами или просто временной интервал на передачу изменений конфигурации в программные и аппаратные компоненты системы) могут различаться. Кроме того, конфигурационные данные и данные текущего состояния могут различаться по срокам действия.

Исходная модель хранилищ данных требует моделирования этих данных в схеме YANG дважды — как объекты config true и config false. Соглашение, принятое в модели данных интерфейса [RFC8343] и модели данных IP [RFC8344], состоит в использовании двух раздельных ветвей с общим корнем — одна ветвь для объектов данных конфигурации, другая для объектов данных текущего состояния.

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

В пересмотренной архитектурной модели хранилищ данных объекты определяются в схеме YANG только один раз, но их независимые экземпляры могут присутствовать в разных хранилищах данных, например, один для настраиваемого значения, а другой для текущего. Это обеспечивает более простое и изящное решение проблемы.

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

3. Терминология

Используемые в документе термины определены ниже. Некоторые термины используют пересмотренные определения из [RFC6241] и [RFC7950] (см. также раздел 4). Эти пересмотренные определения семантически эквивалентны определениям из [RFC6241] и [RFC7950]. Предполагается, что обновлённые определения из этого раздела будут применяться взамен определений [RFC6241] и [RFC7950] при пересмотре этих документов.

datastore — хранилище данных

Концептуальное место для хранения и доступа к информации. Хранилище может быть реализовано, например, в виде файла, базы данных, flash-памяти или их комбинации. Хранилище отображается на экземпляр дерева данных YANG.

schema node — узел схемы

Узел в дереве схемы. Формальное определение приведено в RFC 7950.

datastore schema — схема хранилища данных

Комбинированный набор узлов схемы для всех модулей, поддерживаемых конкретным хранилищем с учётом всех отклонений и активных функций (feature) хранилища.

configuration — конфигурация, данные конфигурации

Данные, которые нужны для перевода устройства из начального состояния в желаемое рабочее состояние. Эти данные моделируются в YANG с использованием узлов config true. Конфигурация может происходить из разных источников.

configuration datastore — хранилище конфигурации

Хранилище данных, содержащее параметры конфигурации.

running configuration datastore — хранилище рабочей конфигурации

Конфигурационное хранилище, содержащее текущие (рабочие) параметры конфигурации устройства. Оно может включать конфигурацию, которая перед применением требует тех или иных преобразований. Это хранилище обозначают <running>.

candidate configuration datastore — хранилище будущей конфигурации, хранилище-кандидат

Конфигурационное хранилище, данные в котором можно изменять без влияния на рабочее хранилище данных устройства. Впоследствии эти данные могут быть переданы в рабочее хранилище. Это хранилище обозначают <candidate>.

startup configuration datastore — хранилище стартовой конфигурации

Конфигурационное хранилище, содержащие данные, которые будут помещены в рабочее хранилище при следующей загрузке устройства. Это хранилище обозначают <startup>.

intended configuration — предполагаемая конфигурация

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

intended configuration datastore — хранилище предполагаемой конфигурации

Конфигурационное хранилище содержащее полную предполагаемую конфигурацию. Это хранилище обозначают <intended>.

configuration transformation — преобразование конфигурации

Дополнение, изменение или удаление данных конфигурации при передаче между хранилищами <running> и <intended>. Примерами конфигурационных преобразований служат удаление из конфигурации неактивных элементов и создание конфигурации из шаблона.

conventional configuration datastore — традиционное (обычное) хранилище данных конфигурации

Одно из хранилищ <running>, <startup>, <candidate> и <intended>. Эти хранилища используют общую схему и протокольные операции позволяют копировать данные между хранилищами. Термин conventional выбран в качестве общего обозначения всех таких хранилищ.

conventional configuration — конфигурация общего назначения

Конфигурационные данные, хранящиеся в любом из традиционных хранилищ.

dynamic configuration datastore — хранилище динамических данных конфигурации

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

dynamic configuration — динамическая конфигурация

Конфигурация, полученная из динамического хранилища.

learned configuration — выведенная конфигурация

Конфигурация, которая была выведена (learned) путём протокольного взаимодействия с другими системами и не является ни традиционной, ни динамической.

system configuration — системная конфигурация

Конфигурация, поставляемая (обеспечиваемая) самой системой.

default configuration — принятая по умолчанию конфигурация

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

applied configuration — применённая конфигурация

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

system state — состояние системы

Дополнительные данные системы, которые не относятся к конфигурационным, это могут быть предназначенные только для чтения параметры состояния или собранная статистика. Состояние системы является временным и меняется в результате взаимодействия с внутренними компонентами или внешними системами. Состояние системы моделируется в YANG с использованием узлов config false.

operational state — рабочее состояние

Комбинация применённой конфигурации и состояния системы.

operational state datastore — хранилище рабочего состояния

Хранилище данные, содержащее полное рабочее состояние устройства и обозначаемое <operational>.

origin — источник, происхождение

Аннотация метаданных, показывающая источник элементе данных.

remnant configuration — остаточная конфигурация

Конфигурация, которая остаётся частью применённой конфигурации в течение некоторого времени после её удаления из предполагаемой или динамической конфигурации. Интервал сохранения может быть минимальным или длиться до тех пор, пока не будут освобождены все использованные удалённой конфигурацией ресурсы (например, сетевые соединения, память, идентификаторы файлов).

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

client — клиент

Объект, который может иметь доступ к данным YANG на сервере с помощью некого протокола управления сетью.

server — сервер

Объект, который предоставляет клиенту доступ к данным YANG с помощью некого протокола управления сетью.

notification — уведомление

Инициированное сервером сообщение, указывающее на некое событие, которое распознал сервер.

remote procedure call — вызов удалённой процедуры

Операция которая может быть вызвана клиентом для выполнения на сервере.

4. Предпосылки

Протокол NETCONF [RFC6241] включает приведённые ниже определения.

datastore — хранилище данных

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

configuration datastore — хранилище конфигурации

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

Язык YANG 1.1 [RFC7950] вносит уточнения для использования NETCONF с YANG (обычное дело, но отметим, что протокол NETCONF был создан раньше YANG).

datastore

При моделировании с использованием YANG хранилище данных реализуется в виде экземпляра дерева данных.

configuration datastore

При моделировании с использованием YANG хранилище данных реализуется в виде экземпляра дерева конфигурационных данных.

[RFC6244] определяет данные операционного состояния, как показано ниже.

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

В параграфе 4.3.3 [RFC6244] рассматривается операционное состояние и среди прочего упоминается возможность рассматривать это состояние, как сохраняемое в другом хранилище данных. В параграфе 4.4 [RFC6244] делается заключение, что во время написания документа рекомендовалось моделирование состояния в виде отдельных листьев и ветвей.

Опыт реализации и запросы операторов [OpState-Reqs] [OpState-Modeling] показали, что модель хранилища, разработанная изначально для NETCONF и уточнённая YANG, требует расширения. В частности, были разработаны понятия предполагаемой конфигурации и применённой конфигурации.

4.1. Исходная модель хранилищ данных

На рисунке 1 показана исходная модель хранилищ данных, используемая сейчас протоколом NETCONF [RFC6241].

+-------------+                 +-----------+
| <candidate> |                 | <startup> |
|  (ct, rw)   |<---+       +--->| (ct, rw)  |
+-------------+    |       |    +-----------+
       |           |       |           |
       |         +-----------+         |
       +-------->| <running> |<--------+
                 | (ct, rw)  |
                 +-----------+
                       |
                       v
                 рабочее состояние  <-- плоскость управления
                    (cf, ro)

ct = config true; cf = config false
rw = read-write; ro = read-only
прямоугольники обозначают хранилища

Рисунок 1.

Отметим, что модель на рисунке упрощена, полномочия read-only (ro) и read-write (rw) представлены с точки зрения клиента на концептуальном уровне. В NETCONF, например, поддержка хранилищ <candidate> и <startup> является не обязательной, а запись в хранилище <running> не разрешена. Кроме того, хранилище <startup> может быть изменено только путём копирования в него хранилища <running> <startup> в стандартизованной модели редактирования хранилищ NETCONF. Протокол RESTCONF не показывает таких различий и вместо этого обеспечивает универсальное хранилище с возможностью записи, которое скрывает редактирование через промежуточное хранилище <candidate> путём прямой записи в <running> или иного механизма, зависящего от реализации. RESTCONF также скрывает, как конфигурация становится постоянной. Отметим, что реализации могут иметь дополнительные хранилища, которые могут распространять изменения на <running>. NETCONF явно указывает «именованные хранилища данных» (named datastore).

Ниже приведены некоторые соображения по результатам использования исходной модели.

  • Операционное состояние не было определено как хранилище данных, хотя были предложения о создании такого хранилища.

  • Операция NETCONF <get> возвращает содержимое хранилища <running> вместе с операционным состоянием. Это требует хранения данных config false и config true в разных ветвях, если данные операционного состояния по сроку жизни отличаются от конфигурационных данных, в также в тех случаях, когда конфигурация применяется не сразу или возникают проблемы с её применением.

  • Некоторые реализации используют фирменные механизмы, которые позволяют клиентам сохранять неактивные данные в хранилище <running>. Концептуально такие данные удаляются перед проверкой пригодности конфигурации.

  • Некоторые реализации используют фирменные механизмы, которые позволяют клиентам определять шаблоны конфигурации в хранилище <running>. Эти шаблоны автоматически раскрываются (преобразуются) системой и полученная в результате конфигурация применяется внутренними средствами.

  • Некоторые операторы отмечали, что для них важно получить успешно применению конфигурацию, которая может быть надмножеством или подмножеством конфигурации в хранилище <running>.

5. Архитектурная модель хранилищ данных

На рисунке 2 представлена новая концептуальная модель хранилищ данных, расширяющая исходную модель в соответствии с набранным при её использовании опытом.

+-------------+                 +-----------+
| <candidate> |                 | <startup> |
|  (ct, rw)   |<---+       +--->| (ct, rw)  |
+-------------+    |       |    +-----------+
       |           |       |           |
       |         +-----------+         |
       +-------->| <running> |<--------+
                 | (ct, rw)  |
                 +-----------+
                       |
                       |        // преобразования конфигурации,
                       |        // например, удаление узлов с 
                       |        // меткой "inactive", раскрытие
                       |        // шаблонов
                       v
                 +------------+
                 | <intended> | // нужна проверка на пригодность
                 | (ct, ro)   |
                 +------------+
                       |        // применение изменений; может
                       |        // от локальных факторов, например,
                       |        // отсутствие ресурсов, задержки
                       |
  хранилища            |   +-------- выведенная конфигурация
  динамической         |   +-------- конфигурация системы
  конфигурации ---+    |   +-------- конфигурация по умолчанию
                  |    |   |
                  v    v   v
               +---------------+
               | <operational> | <-- состояние системы
               | (ct + cf, ro) |
               +---------------+

     ct = config true; cf = config false
     rw = read-write; ro = read-only
     прямоугольники показывают именованные хранилища

Рисунок 2.


5.1. Традиционные хранилища конфигурации

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

  • <running>

  • <candidate>

  • <startup>

  • <intended>

В будущих документах могут быть определены дополнительные хранилища.

Поток данных между хранилищами описан в разделе 5.

Конкретные протоколы могут определять явные операции копирования между хранилищами (например, NETCONF <copy-config>.

5.1.1. Хранилище стартовой конфигурации (<startup>)

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

Хранилище стартовой конфигурации может поддерживаться не всеми протоколами и реализациями.

На устройствах с энергонезависимой памятью содержимое хранилища <startup> обычно будет сохраняться при перезагрузке устройства с использованием этого хранилища. Во время загрузки устройство помещает стартовую конфигурацию в хранилище <running>. Для сохранения новой стартовой конфигурации данные копируются в <startup> с помощью явной или неявной операции протокола.

5.1.2. Хранилище будущей конфигурации (<candidate>)

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

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

Хранилище <candidate> обычно не сохраняется при перезагрузке устройства, даже если для него используется энергонезависимая память. Если хранилище <candidate> сохраняется в такой памяти, в процессе перезагрузки оно заменяется содержимым хранилища <running>.

5.1.3. Хранилище рабочей конфигурации (<running>)

Хранилище рабочей конфигурации <running> представляет собой хранилище с текущей конфигурацией устройства. Оно может содержать конфигурацию, которая перед применением требует преобразования (например, удаление неактивных элементов или раскрытие шаблонов). Однако хранилище <running> всегда должно быть пригодным деревом конфигурационных данных, как указано в параграфе 8.1 [RFC7950].

Хранилище <running> должно поддерживаться, если устройство настраивается с использованием традиционного хранилища конфигурации.

Если устройство не имеет отдельно хранилища <startup> и доступна энергонезависимая память, такое устройство обычно будет использовать эту память для сохранения <running> в процессе перезагрузки.

5.1.4. Хранилище предполагаемой конфигурации (<intended>)

Хранилище предполагаемой конфигурации <intended> открыто только для чтения. Оно представляет конфигурацию после выполнения всех преобразования в <running> (например, расширения шаблонов и удаления неактивных компонент), которую система пытается применить.

Хранилище <intended> тесно связано с <running>. При записи данных в хранилище <running> сервер должен незамедлительно обновить и проверить на пригодность хранилище <intended>.

Содержимое <intended> может также обновляться независимо от <running>, если воздействие преобразований конфигурации меняется, но хранилище <intended> всегда должен быть пригодным деревом данных конфигурации, как указано в параграфе 8.1 [RFC7950].

В простых реализациях хранилища <running> и <intended> идентичны.

Содержимое <intended> также связано с подмножеством config true хранилища <operational>, поэтому клиент может определить, в какой степени предполагаемая конфигурация соответствует текущей, просто проверяя, какая часть содержимого <intended> присутствует в <operational>.

Хранилище <intended> не сохраняется при перезагрузке — его привязка к <running> делает это ненужным.

В настоящее время не определено стандартных механизмов воздействия на хранилище <intended> так, чтобы оно отличалось от <running>, но данная архитектура позволяет определить такие механизмы.

Примером такого механизма может служить поддержка маркировки неактивных узлов в хранилище <running>. Неактивные узлы не будут копироваться в хранилище <intended>. Вторым примером является поддержка шаблонов, которые могут выполнять преобразования конфигурации из <running> для записи в хранилище <intended>.

5.2. Хранилища динамической конфигурации

Модель принимает необходимость хранилищ динамической конфигурации, которые по определению не являются частью постоянной конфигурации устройства. Иногда такие хранилища называют эфемерными (ephemeral datastore), поскольку хранящаяся в них информация теряется при перезагрузке. Хранилища динамической конфигурации взаимодействуют с остальной системой через хранилище <operational>.

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

5.3. Хранилище операционного состояния (<operational>)

Хранилище операционного состояния (<operational>) открыто лишь для чтения и включает все узлы config true и config false, определённые в схеме хранилища данных. В исходной модели NETCONF модель операционного состояния содержит только узлы config false. Причиной включения узлов config true является потребность в представлении рабочих параметров без их дублирования в модели данных.

Хранилище <operational> содержит данные состояния и конфигурацию, реально используемую системой. Это включает применённую конфигурацию из хранилища <intended>, выведенную (learned) и представленную системой конфигурацию, а также значения, принятые по умолчанию, которые определены любыми поддерживаемыми моделями данных. В дополнение к этому <operational> содержит также применённую конфигурацию из хранилища динамической конфигурации.

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

Запросы на поиск узлов из хранилища <operational> всегда возвращают используемое значение для существующих узлов, независимо от наличия в модуле YANG принятых по умолчанию значений. Если для данного узла значение не возвращено, это означает, что узел не используется устройством.

Интерпретация слов «используется системой» (in use) зависит от определения схемы и реализации устройства. Обычно функциональность, которая разрешена (включена) и работает в системе, считается используемой. И наоборот, функциональность, которая не включена и не работает считается «не используемой», поэтому её не следует включать в <operational>.

Для хранилища <operational> следует соблюдать любые ограничения, указанные в модели данных, но с учётом главной цели возвращать «используемые» значения, возможны случаи, когда такие ограничения могут быть нарушены при некоторых обстоятельствах (например, использование аномального значения, изменении структуры списка или наличии остаточной конфигурации (см. параграф 5.3.1)). Отметим, что такие отклонения следует допускать лишь в тех случаях, когда заранее известно, что устройство не полностью соответствует схеме <operational>.

Нарушаться могут только семантические ограничения. К ним относятся операторы YANG when, must, mandatory, unique, min-elements и max-elements, а также уникальность значений ключей.

Синтаксические ограничения, включая иерархическую организацию, идентификаторы и ограничения по типам, нарушать недопустимо. Если узел в хранилище <operational> не соответствует синтаксическим ограничениям, недопустимо возвращать его, а для информирования об ошибке следует применять другие механизмы.

Хранилище <operational> не сохраняется при перезагрузке устройства.

5.3.1. Остаточная конфигурация

При изменении конфигурации может потребоваться некоторое время на прохождение через хранилище <operational>. В этом интервале хранилище <operational> может одновременно содержать узлы предшествующей и текущей конфигурации, насколько возможно точно отслеживая текущую работу устройства. Остаточные данные предыдущей конфигурации будут сохраняться до тех пор, пока система не освободит ресурсы, использованные недавно удалённой конфигурацией (например, сетевые соединения, память, файлы).

Остаточная конфигурация является типичным примером, где семантические ограничения, определённые в модели данных, не могут быть применены для хранилища <operational>, поскольку в системе может сохраняться конфигурация, ограничения которой были пригодны для прежнего варианта, но недействительны в текущей конфигурации. Поскольку ограничения узлов config false могут быть связаны с узлами config true, остаточная конфигурация может вызывать нарушение этих ограничений.

5.3.2. Отсутствующие ресурсы

Конфигурация в <intended> может указывать ресурсы, которые не доступны или физически отсутствуют. В такой ситуации соответствующие части <intended> не применяются. Данные этих разделов присутствуют в <intended>, но не появляются в <operational>.

Типичным примером является конфигурация интерфейса, который в настоящее не присутствует. В этом случае конфигурация интерфейса остаётся в хранилище <intended>, но не включается в <operational>.

Отметим, что пригодность конфигурации не может зависеть от текущего состояния таких ресурсов, поскольку это приводило бы в непригодности конфигурации в случае удаления ресурса. Это неприемлемо, особенно с учётом того, что перезагрузка такого устройства будет приводить к его перезапуску с непригодной конфигурацией. Поэтому конфигурации с отсутствующими ресурсами разрешаются для хранилищ <running> и <intended>, но эти ресурсы не могут присутствовать в <operational>.

5.3.3. Контролируемые системой ресурсы

Иногда ресурсы, контролируемые системой и соответствующие данные появляются (и исчезают) в хранилище <operational> динамически. Если контролируемый системой ресурс имеет соответствующую конфигурацию в <intended> при его появлении, система попытается применить эту конфигурацию и это в конечном итоге приведёт к её появлению в хранилище <operational> (если применение пройдёт успешно).

5.3.4. Аннотация метаданных источника

При передаче конфигурации в хранилище <operational> она концептуально помечается аннотацией метаданных [RFC7952]Ю указывающей источник. Источник применяет все узлы за исключением контейнеров отсутствия. Аннотация метаданных origin определена в разделе 7. Значениями служат отождествления YANG, перечисленные ниже.

  • origin — абстрактное базовое отождествление, из которого выведено другое отождествление источника.

  • intended — представляет конфигурацию из хранилища <intended>.

  • dynamic — представляет конфигурацию из хранилища динамической конфигурации.

  • system — представляет конфигурацию, обеспеченную самой системой. Примеры системной конфигурации включают всегда присутствующий интерфейс loopback или конфигурацию интерфейса, которая создаётся автоматически при наличии оборудования в устройстве.

  • learned — представляет конфигурацию, которая была выведена через протокольные взаимодействия с другими системами (включая такие взаимодействия как согласование канального уровня, протоколы маршрутизации, DHCP).

  • default — представляет конфигурацию с применением значений, принятых по умолчанию в модели данных, используя значения в операторе default или любые значения, описанные в операторе description. Этот источник лишь про отсутствии других источников конфигурации.

  • unknown — представляет конфигурацию, для которой система не может определить источник.

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

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

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

Если для отдельного узла конфигурации соответствующий оператор description в модуле YANG указывает, что согласованное протоколом значение переписывает значение из конфигурации, в качестве источника следует указывать learned, даже при совпадении выведенного значения с указанным в конфигурации.

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

Если устройство не может точно указать источник данных для отдельного узла конфигурации, следует указывать источник unknown.

6. Воздействие на YANG

6.1. Контекст XPath

Этот параграф обновляет параграф 6.4.1 из RFC 7950.

Если сервер реализует определённую в этом документе архитектуру, доступные деревья для некоторых вариантов контекста XPath уточняются как показано ниже.

  • Если выражение XPath определено в субоператоре узла данных, который представляет состояние системы, доступным деревом является все операционное состояние сервера. Корневой узел имеет в качестве потомков узлы верхнего уровня всех модулей.

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

  • Если выражение XPath определено в субоператоре оператора input внутри оператора rpc или action, доступным деревом будет экземпляр RPC или операции и все операционное состояние сервера. Корневой узел имеет в качестве потомков узлы верхнего уровня всех модулей. Кроме того, для RPC корневой узел имеет в качестве потомка также узел, который представляет определяемую операцию RPC. Этот узел имеет в качестве потомков входные параметры операции.

  • Если выражение XPath определено в субоператоре оператора output внутри оператора rpc или action, доступным деревом будет экземпляр RPC или операции и все операционное состояние сервера. Корневой узел имеет в качестве потомков узлы верхнего уровня всех модулей. Кроме того, для RPC корневой узел имеет в качестве потомка также узел, который представляет определяемую операцию RPC. Этот узел имеет в качестве потомков выходные результаты операции.

6.2. Вызовы операций и RPC

Этот параграф обновляет параграф 7.15 из RFC 7950.

Операции всегда вызываются к контексте хранилища операционного состояния. Узел, для которого вызывается операция, должен существовать в хранилище операционного состояния.

Отметим, что этот документ никак не ограничивает результат вызова RPC или операции. Например, можно определить RPC для изменения содержимого того или иного хранилища данных.

7. Модули YANG

   <CODE BEGINS> file "ietf-datastores@2018-02-14.yang"

   module ietf-datastores {
     yang-version 1.1;
     namespace "urn:ietf:params:xml:ns:yang:ietf-datastores";
     prefix ds;

     organization
       "IETF Network Modeling (NETMOD) Working Group";

     contact
       "WG Web:   <https://datatracker.ietf.org/wg/netmod/> 

        WG List:  <mailto:netmod@ietf.org> 

        Author:   Martin Bjorklund
                  <mailto:mbj@tail-f.com> 

        Author:   Juergen Schoenwaelder
                  <mailto:j.schoenwaelder@jacobs-university.de> 

        Author:   Phil Shafer
                  <mailto:phil@juniper.net> 

        Author:   Kent Watsen
                  <mailto:kwatsen@juniper.net> 

        Author:   Rob Wilton
                  <rwilton@cisco.com>"; 

     description
       "Этот модуль YANG задает набор идентификаторов хранилищ данных.

        Авторские права (Copyright (c) 2018) принадлежат IETF Trust
        и лицам, указанным в качестве авторов кода. Все права защищены.

        Распространение и использование в исходной или двоичной форме с
        изменениями или без таковых разрешено в соответствии с лицензией
        Simplified BSD, изложенной в разделе 4  IETF Trust's Legal
        Provisions применительно к документам IETF
        (http://trustee.ietf.org/license-info). 
 
        Эта версия данного модуля YANG является частью RFC 8342, где
        правовые вопросы рассмотрены более полно.";

     revision 2018-02-14 {
       description
         "Initial revision.";
       reference
         "RFC 8342: Network Management Datastore Architecture (NMDA)";
     }

     /*
      * Отождествления (идентификаторы)
      */

     identity datastore {
       description
         "Абстрактный базовый идентификатор для хранилища данных.";
     }

     identity conventional {
       base datastore;
       description
         "Абстрактный базовый идентификатор для традиционного
          хранилища данных.";
     }

     identity running {
       base conventional;
       description
         "Хранилище рабочей конфигурации.";
     }

     identity candidate {
       base conventional;
       description
         "Хранилище конфигурации-кандидата.";
     }

     identity startup {
       base conventional;
       description
         "Хранилище данных стартовой конфигурации.";
     }

     identity intended {
       base conventional;
       description
         "Хранилище данных предполагаемой конфигурации.";
     }

     identity dynamic {
       base datastore;
       description
         "Абстрактный базовый идентификатор для хранилища
          данных динамической конфигурации.";
     }

     identity operational {
       base datastore;
       description
         "Хранилище данных рабочего состояния.";
     }

     /*
      * Определения типов
      */

     typedef datastore-ref {
       type identityref {
         base datastore;
       }
       description
         "Ссылка на идентификатор хранилища данных.";
     }
   }

   <CODE ENDS>

   <CODE BEGINS> file "ietf-origin@2018-02-14.yang"

   module ietf-origin {
     yang-version 1.1;
     namespace "urn:ietf:params:xml:ns:yang:ietf-origin";
     prefix or;

     import ietf-yang-metadata {
       prefix md;
     }

     organization
       "IETF Network Modeling (NETMOD) Working Group";

     contact
       "WG Web:   <https://datatracker.ietf.org/wg/netmod/> 

        WG List:  <mailto:netmod@ietf.org> 

        Author:   Martin Bjorklund
                  <mailto:mbj@tail-f.com> 

        Author:   Juergen Schoenwaelder
                  <mailto:j.schoenwaelder@jacobs-university.de> 

        Author:   Phil Shafer
                  <mailto:phil@juniper.net> 

        Author:   Kent Watsen
                  <mailto:kwatsen@juniper.net> 

        Author:   Rob Wilton
                  <rwilton@cisco.com>"; 

     description
       "Этот модуль YANG задает аннотацию метаданных origin и набор
        идентификаторов для значения origin.

        Авторские права (Copyright (c) 2018) принадлежат IETF Trust
        и лицам, указанным в качестве авторов кода. Все права защищены.

        Распространение и использование в исходной или двоичной форме с
        изменениями или без таковых разрешено в соответствии с лицензией
        Simplified BSD, изложенной в разделе 4  IETF Trust's Legal
        Provisions применительно к документам IETF
        (http://trustee.ietf.org/license-info). 
 
        Эта версия данного модуля YANG является частью RFC 8342, где
        правовые вопросы рассмотрены более полно.";

     revision 2018-02-14 {
       description
         "Initial revision.";
       reference
         "RFC 8342: Network Management Datastore Architecture (NMDA)";
     }

     /*
      * Отождествления (идентификаторы)
      */

     identity origin {
       description
         "Абстрактный базовый идентификатор для аннотации источника.";
     }

     identity intended {
       base origin;
       description
         "Конфигурация из хранилища intended.";
     }

     identity dynamic {
       base origin;
       description
         "Конфигурация из хранилища dynamic.";
     }

     identity system {
       base origin;
       description
         "Конфигурация самой системы.

          Примеры конфигурации системы включают конфигурацию, 
          примененную к всегда имеющемуся интерфейсу loopback или 
          автоматически созданную конфигурацию присутствующего
          в устройстве оборудования.";
     }

     identity learned {
       base origin;
       description
         "Конфигурация, полученная из протокольных взаимодействий с
          другими устройствами, а не из хранилища intended или иного
          хранилища динамической конфигурации.

          Примеры протоколов изучения конфигурации включают согласование
          на канальном уровне, протоколы маршрутизации и DHCP.";
     }

     identity default {
       base origin;
       description
         "Конфигурация, которая не была настроена или получена от
          протокола, а задана по умолчанию. Включает значения операторов
          default и значения, полученные из объяснений в операторах
          description.";
     }

     identity unknown {
       base origin;
       description
         "Конфигурация, для которой система не может узнать источник.";
     }

     /*
      * Определения типов
      */

     typedef origin-ref {
       type identityref {
         base origin;
       }
       description
         "Ссылка на идентификатор источника.";
     }

     /*
      * Аннотации метаданных
      */

     md:annotation origin {
       type origin-ref;
       description
         "Аннотация origin может присутствовать в любом узле данных
          конфигурации хранилища рабочего состояния. Она указывает,
          откуда взят узел. Если источник не указан для узла данных
          конфигурации, принимается источник родительского узла в
          дереве данных. Источник для узлов данных конфигурации 
          верхнего уровня должен указываться всегда.";
     }
   }

   <CODE ENDS>

8. Взаимодействие с IANA

8.1. Обновление реестра IETF XML Registry

Этот документ регистрирует два URI в реестре IETF XML Registry [RFC3688] в соответствии с форматом [RFC3688]

      URI: urn:ietf:params:xml:ns:yang:ietf-datastores
      Registrant Contact: The IESG.
      XML: N/A; the requested URI is an XML namespace.

      URI: urn:ietf:params:xml:ns:yang:ietf-origin
      Registrant Contact: The IESG.
      XML: N/A; the requested URI is an XML namespace.

8.2. Обновление реестра YANG Module Names Registry

Документ регистрирует два модуля YANG в реестре YANG Module Names [RFC6020] в соответствии с [RFC6020]

      name:         ietf-datastores
      namespace:    urn:ietf:params:xml:ns:yang:ietf-datastores
      prefix:       ds
      reference:    RFC 8342

      name:         ietf-origin
      namespace:    urn:ietf:params:xml:ns:yang:ietf-origin
      prefix:       or
      reference:    RFC 8342

9. Вопросы безопасности

В этом документе обсуждается архитектурная модель для хранилищ данных сетевого управления, используемых протоколами NETCONF/RESTCONF и языком YANG. Это не оказывает влияния на безопасность Internet.

Хотя в этом документе заданы модули YANG, эти модули определяют лишь отождествления и аннотацию метаданных. По этой причине рекомендации по безопасности YANG [YANG-SEC] не используются.

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

10. Литература

10.1. Нормативные документы

[RFC2119] Bradner, S., «Key words for use in RFCs to Indicate Requirement Levels», BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, <https://www.rfc-editor.org/info/rfc2119>.

[RFC6241] Enns, R., Ed., Bjorklund, M., Ed., Schoenwaelder, J., Ed., and A. Bierman, Ed., «Network Configuration Protocol (NETCONF)», RFC 6241, DOI 10.17487/RFC6241, June 2011, <https://www.rfc-editor.org/info/rfc6241>.

[RFC7950] Bjorklund, M., Ed., «The YANG 1.1 Data Modeling Language», RFC 7950, DOI 10.17487/RFC7950, August 2016, <https://www.rfc-editor.org/info/rfc7950>.

[RFC7952] Lhotka, L., «Defining and Using Metadata with YANG», RFC 7952, DOI 10.17487/RFC7952, August 2016, <https://www.rfc-editor.org/info/rfc7952>.

[RFC8040] Bierman, A., Bjorklund, M., and K. Watsen, «RESTCONF Protocol», RFC 8040, DOI 10.17487/RFC8040, January 2017, <https://www.rfc-editor.org/info/rfc8040>.

[RFC8174] Leiba, B., «Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words», BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017, <https://www.rfc-editor.org/info/rfc8174>.

[W3C.REC-xml-20081126] Bray, T., Paoli, J., Sperberg-McQueen, M., Maler, E., and F. Yergeau, «Extensible Markup Language (XML) 1.0 (Fifth Edition)», World Wide Web Consortium Recommendation REC-xml-20081126, November 2008, <https://www.w3.org/TR/2008/REC-xml-20081126>.

10.2. Дополнительная литература

[NETMOD-Operational] Bjorklund, M. and L. Lhotka, «Operational Data in NETCONF and YANG», Work in Progress, draft-bjorklund-netmod-operational-00, October 2012.

[OpState-Enhance] Watsen, K., Bierman, A., Bjorklund, M., and J. Schoenwaelder, «Operational State Enhancements for YANG, NETCONF, and RESTCONF», Work in Progress, draft-kwatsen-netmod-opstate-02, February 2016.

[OpState-Modeling] Shakir, R., Shaikh, A., and M. Hines, «Consistent Modeling of Operational State Data in YANG», Work in Progress, draft-openconfig-netmod-opstate-01, July 2015.

[OpState-Reqs] Watsen, K. and T. Nadeau, «Terminology and Requirements for Enhanced Handling of Operational State», Work in Progress, draft-ietf-netmod-opstate-reqs-04, January 2016.

[RFC3688] Mealling, M., «The IETF XML Registry», BCP 81, RFC 3688, DOI 10.17487/RFC3688, January 2004, <https://www.rfc-editor.org/info/rfc3688>.

[RFC6020] Bjorklund, M., Ed., «YANG — A Data Modeling Language for the Network Configuration Protocol (NETCONF)», RFC 6020, DOI 10.17487/RFC6020, October 2010, <https://www.rfc-editor.org/info/rfc6020>.

[RFC6244] Shafer, P., «An Architecture for Network Management Using NETCONF and YANG», RFC 6244, DOI 10.17487/RFC6244, June 2011, <https://www.rfc-editor.org/info/rfc6244>.

[RFC8343] Bjorklund, M., «A YANG Data Model for Interface Management», RFC 8343, DOI 10.17487/RFC8343, March 2018, <https://www.rfc-editor.org/info/rfc8343>.

[RFC8344] Bjorklund, M., «A YANG Data Model for IP Management», RFC 8344, DOI 10.17487/RFC8344, March 2018, <https://www.rfc-editor.org/info/rfc8344>.

[With-config-state] Wilton, R., «»With-config-state» Capability for NETCONF/RESTCONF», Work in Progress, draft-wilton-netmod-opstate-yang-02, December 2015.

[YANG-SEC] IETF, «YANG Security Guidelines», <https://trac.ietf.org/trac/ops/wiki/yang-security-guidelines>.

Приложение A. Рекомендации по определению хранилищ

Определение нового хранилища в рамках данной архитектуры следует приводить в специальном документе (например, RFC). Когда это имеет смысл, в одном документе может определяться множество хранилищ (например, когда эти хранилища логически связаны). В определении каждого хранилища должны включать описанные ниже аспекты.

A.1. Определение модулей YANG, применимых для хранилища

Для хранилища данных могут быть применимы не все модули YANG. Некоторые хранилища могут вносить ограничения на использование моделей данных. Если для хранилища желательно целевое использование некоторого подмножества, документация должна указывать это.

A.2. Определение применимого подмножества операторов YANG

По умолчанию данные в хранилище моделируются с использованием всех операторов YANG в доступных модулях YANG. Однако возможно задание критериев, которым должны удовлетворять операторы YANG для включения в хранилище. Например, могут разрешаться только узлы config true или узлы config false, имеющие конкретное расширение YANG.

A.3. Определение способов актуализации данных

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

Например, рисунок 2 показывает хранилища динамической конфигурации, подаваемые в хранилище <operational>. Способ такой передачи определяет конкретным хранилищем динамической конфигурации. В некоторых случаях это может происходить неявно просто при попадании данных в хранилище динамической конфигурации, а в других случаях может потребоваться явное действие (например, RPC).

A.4. Определение применимых протоколов

По умолчанию предполагается что взаимодействие с хранилищами может выполняться с обоими протоколами NETCONF и RESTCONF. Однако можно задать использование лишь одного конкретного протокола (например, ForCES5), подмножества операций протокола или доступных возможностей (например, без блокировки или фильтрации по XPath).

A.5. Определение отождествлений YANG для хранилища

Хранилище должно быть определено с использованием отождествления YANG, использующего ds:datastore или одно из производных от него отождествлений. Это отождествление требуется, чтобы по по нему можно было ссылаться на хранилище в операциях протокола (например, <get-data>).

Хранилище может быть также определено с использованием в качестве базы отождествления or:origin или производного от него отождествления. Такое отождествление требуется, если хранилище взаимодействует с <operational>, чтобы по нему можно указать хранилище в атрибуте метаданных origin, определённом в разделе 7.

Примеры использования этих рекомендаций приведены в Приложении B.

Приложение B. Пример эфемерного хранилища

В этом приложении описаны примеры хранилища динамической конфигурации с использованием рекомендаций из Приложения A. Для краткости представлен сокращённый пример, предполагается что будет выпущен отдельный документ RFC с полным описанием.

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

Свойства примера «эфемерного» хранилища.

Имя

Значение

Name

ephemeral

YANG modules

all (default)

YANG nodes

all «config true» data nodes

How applied

changes automatically propagated to <operational>

Protocols

NETCONF/RESTCONF (default)

Defining YANG module

«example-ds-ephemeral»

   module example-ds-ephemeral {
     yang-version 1.1;
     namespace "urn:example:ds-ephemeral";
     prefix eph;

     import ietf-datastores {
       prefix ds;
     }
     import ietf-origin {
       prefix or;
     }

     // Идентификатор хранилища данных
     identity ds-ephemeral {
       base ds:dynamic;
       description
         "Эфемерное хранилище динамической конфигурации.";
     }

     // Идентификатор источника
     identity or-ephemeral {
       base or:dynamic;
       description
         "Данные из эфемерного хранилища динамической конфигурации.";
     }
   }

Приложение C. Примеры

Использование хранилищ является сложной задачей и многие тонкие эффекты проще показать на примерах. В этом приложении представлена серия примеров моделей данных с некоторым содержимым различных хранилищ.

Фрагменты XML [W3C.REC-xml-20081126] представлены лишь для иллюстрации.

C.1. Пример хранилища System

Ниже показан используемый в примере функциональный модуль.

   module example-system {
     yang-version 1.1;
     namespace urn:example:system;
     prefix sys;

     import ietf-inet-types {
       prefix inet;
     }

     container system {
       leaf hostname {
         type string;
       }

       list interface {
         key name;

         leaf name {
           type string;
         }

         container auto-negotiation {
           leaf enabled {
             type boolean;
             default true;
           }
           leaf speed {
             type uint32;
             units mbps;
             description
               "Аносируемая скорость в Мбит/с.";
           }
         }

         leaf speed {
           type uint32;
           units mbps;
           config false;
           description
             "Скорость интерфейса в Мбит/с .";
         }

         list address {
           key ip;

           leaf ip {
             type inet:ip-address;
           }
           leaf prefix-length {
             type uint8;
           }
         }
       }
     }
   }

Оператор настроил имя хоста и два интерфейса и хранилище <intended> имеет вид

   <system xmlns="urn:example:system">

     <hostname>foo.example.com</hostname>

     <interface>
       <name>eth0</name>
       <auto-negotiation>
         <speed>1000</speed>
       </auto-negotiation>
       <address>
         <ip>2001:db8::10</ip>
         <prefix-length>64</prefix-length>
       </address>
     </interface>

     <interface>
       <name>eth1</name>
       <address>
         <ip>2001:db8::20</ip>
         <prefix-length>64</prefix-length>
       </address>
     </interface>

   </system>

Система обнаружила, что аппаратная часть одного из настроенных интерфейсов (eth1) ещё отсутствует, поэтому настройка данного интерфейса не была применена. После этого система получила имя хоста и дополнительный адрес IP для eth0 по протоколу DHCP. В дополнение к установке принятого по умолчанию значения для листа управления автоматическим согласованием (auto-negotiation) в системе также автоматически создан интерфейс loopback. Все упомянутое нашло отражение в хранилище <operational>. Отметим, что атрибут метаданных origin для некоторых узлов данных config true унаследован от их родителей.

   <system
       xmlns="urn:example:system"
       xmlns:or="urn:ietf:params:xml:ns:yang:ietf-origin">

     <hostname or:origin="or:learned">bar.example.com</hostname>

     <interface or:origin="or:intended">
       <name>eth0</name>
       <auto-negotiation>
         <enabled or:origin="or:default">true</enabled>
         <speed>1000</speed>
       </auto-negotiation>
       <speed>100</speed>
       <address>
         <ip>2001:db8::10</ip>
         <prefix-length>64</prefix-length>
       </address>
       <address or:origin="or:learned">
         <ip>2001:db8::1:100</ip>
         <prefix-length>64</prefix-length>
       </address>
     </interface>

     <interface or:origin="or:system">
       <name>lo0</name>
       <address>
         <ip>::1</ip>
         <prefix-length>128</prefix-length>
       </address>
     </interface>

   </system>

C.2. Пример BGP

Рассмотрим фрагмент функционального модуля BGP

       container bgp {
         leaf local-as {
           type uint32;
         }
         leaf peer-as {
           type uint32;
         }
         list peer {
           key name;
           leaf name {
             type inet:ip-address;
           }
           leaf local-as {
             type uint32;
             description
               "... По умолчанию ../local-as.";
           }
           leaf peer-as {
             type uint32;
             description
               "... По умолчанию ../peer-as.";
           }
           leaf local-port {
             type inet:port;
           }
           leaf remote-port {
             type inet:port;
             default 179;
           }
           leaf state {
             config false;
             type enumeration {
               enum init;
               enum established;
               enum closing;
             }
           }
         }
       }

В этой модели оба узла bgp/peer/local-as и bgp/peer/peer-as имеют комплексные иерархические значения, позволяя пользователю задать используемые по умолчанию значения для всех партнёров в одном месте.

Модель также следует шаблону полного объединения узлов состояния (config false) и узлов конфигурации (config true). Здесь нет отдельной иерархии bgp-state и связанного с ней повтора узлов сдерживания ограничений и именования. Это делает модель более простой и удобочитаемой.

C.2.1. Хранилища данных

Каждое хранилище даёт разные представления этих узлов. Хранилище <running> будет содержать конфигурацию, заданную оператором (например, один партнёр BGP). Хранилище <intended> концептуально будет содержать все проверенные на пригодность данные после исключения не предназначенных для такой проверки данных и выполнения всех локальных механизмов преобразования шаблонов. Хранилище <operational> будет показывать данные из <intended>, а также все узлы config false.

C.2.2. Добавление партнёра

Если оператор указал одного партнёра BGP, этот партнёр будет виден в обоих хранилищах <running> и <intended>. Он может также присутствовать в <candidate>, если сервер поддерживает хранилище для будущих конфигураций. Поиск партнёра будет возвращать только заданные пользователем значения.

Между появлением партнёра в хранилищах <running> и <intended> не должно быть задержки.

Добавим в хранилище <running> представленную ниже информацию.

     <bgp>
       <local-as>64501</local-as>
       <peer-as>64502</peer-as>
       <peer>
         <name>2001:db8::2:3</name>
       </peer>
     </bgp>
C.2.2.1. Хранилище <operational>

Операционное хранилище будет содержать полностью раскрытые данные партнёра, включая узлы config false. В нашем примере это означает появление узла state.

Кроме того, хранилище <operational> будет содержать реально используемые (currently in use) значения для всех узлов. Это значит, что local-as и peer-as будут заполнены даже в том случае, когда их значения не заданы в <intended>. При отсутствии bgp/peer/local-as будет использовано значение bgp/local-as, а при отсутствии bgp/peer/peer-as — bgp/peer-as. В операционном представлении это означает, что каждый партнёр будет иметь значения для своих local-as и peer-as, даже если эти значения не будут заданы явно, но будут представлены в bgp/local-as и bgp/peer-as.

Каждый из партнёров BGP имеет связанное с ним соединение TCP, использующее значения local-port и remote-port из <intended>. Если эти значения не представлены, они будут выбраны системой. После организации соединения хранилище <operational> будет содержать текущие значения для local-port и remote-port, независимо от их происхождения. Если значения выбраны системой, атрибут origin будет указывать system. Перед организацией соединения один или оба узла могут отсутствовать, поскольку система может ещё не иметь их значений.

     <bgp xmlns:or="urn:ietf:params:xml:ns:yang:ietf-origin"
          or:origin="or:intended">
       <local-as>64501</local-as>
       <peer-as>64502</peer-as>
       <peer>
         <name>2001:db8::2:3</name>
         <local-as or:origin="or:default">64501</local-as>
         <peer-as or:origin="or:default">64502</peer-as>
         <local-port or:origin="or:system">60794</local-port>
         <remote-port or:origin="or:default">179</remote-port>
         <state>established</state>
       </peer>
     </bgp>

C.2.3. Удаление партнёра

При изменении конфигурации может потребоваться время на прохождение этих изменений через вовлечённые в процесс программные компоненты. В этом интервале времени необходимо сохранять точное представление о работе устройства. Хранилище <operational> будет содержать узлы предыдущей и текущей конфигурации, насколько возможно точно отслеживая текущее операционное состояние устройства.

Рассмотрим сценарий с удалением партнёра BGP. В этом случае операционное состояние будет по-прежнему отражать наличие этого партнёра до тех пор, пока не будут освобождены ресурсы закрываемого партнерского соединения. В течение переходного периода текущие значения данных будут видны в хранилище <operational> с атрибутом origin, указывающим происхождение исходных данных.

     <bgp xmlns:or="urn:ietf:params:xml:ns:yang:ietf-origin"
          or:origin="or:intended">
       <local-as>64501</local-as>
       <peer-as>64502</peer-as>
       <peer>
         <name>2001:db8::2:3</name>
         <local-as or:origin="or:default">64501</local-as>
         <peer-as or:origin="or:default">64502</peer-as>
         <local-port or:origin="or:system">60794</local-port>
         <remote-port or:origin="or:default">179</remote-port>
         <state>closing</state>
       </peer>
     </bgp>

После освобождения ресурсов и закрытия соединения данные о партнёре удаляются из хранилища <operational>.

C.3. Пример интерфейса

В этом параграфе используется простая модель данных интерфейса.

     container interfaces {
       list interface {
         key name;
         leaf name {
           type string;
         }
         leaf description {
           type string;
         }
         leaf mtu {
           type uint16;
         }
         leaf-list ip-address {
           type inet:ip-address;
         }
       }
     }

C.3.1. Заранее представленные интерфейсы

Одной из проблем сетевых устройств является поддержка сменных узлов (FRU6), которые могут добавляться и удаляться из устройства без его перезагрузки и нарушения нормальной работы. Эти FRU обычно являются интерфейсными модулями (платами) и устройства поддерживают упреждающее представление этих интерфейсов.

Если клиент создаёт интерфейс et-0/0/0, которого в этот момент нет физически, хранилище <intended> может содержать представленную ниже информацию.

     <interfaces>
       <interface>
         <name>et-0/0/0</name>
         <description>Тестовый интерфейс</description>
       </interface>
     </interfaces>

Поскольку интерфейса нет, эти данные не будут присутствовать в хранилище <operational>.

При установке FRU с этим интерфейсом система обнаружит его и обработает соответствующую конфигурацию. Хранилище <operational> будет содержать данные из <intended>, а также узлы, добавленные системой типа текущего значения MTU для интерфейса.

     <interfaces xmlns:or="urn:ietf:params:xml:ns:yang:ietf-origin"
                 or:origin="or:intended">
       <interface>
         <name>et-0/0/0</name>
         <description>Тестовый интерфейс</description>
         <mtu or:origin="or:system">1500</mtu>
       </interface>
     </interfaces>

Если FRU удаляется, данные интерфейса исключаются из хранилища <operational>.

C.3.2. Предоставляемые системой интерфейсы

Рассмотрим систему, предоставляющую петлевой интерфейс lo0 с принятым по умолчанию адресом IPv4 127.0.0.1 и IPv6 ::1. Система будет обеспечивать конфигурацию для этого интерфейса, если для него нет данных в <intended>.

При отсутствии конфигурации для lo0 в хранилище <intended>, <operational> будет показывать предоставляемые системой данные.

     <interfaces xmlns:or="urn:ietf:params:xml:ns:yang:ietf-origin"
                 or:origin="or:intended">
       <interface or:origin="or:system">
         <name>lo0</name>
         <ip-address>127.0.0.1</ip-address>
         <ip-address>::1</ip-address>
       </interface>
     </interfaces>

Если конфигурация для lo0 имеется в <intended>, хранилище <operational> будет показывать эти данные с источником intended. Если значение ip-address не было задано, предоставленные системой значения будут иметь вид

     <interfaces xmlns:or="urn:ietf:params:xml:ns:yang:ietf-origin"
                 or:origin="or:intended">
       <interface>
         <name>lo0</name>
         <description>loopback</description>
         <ip-address or:origin="or:system">127.0.0.1</ip-address>
         <ip-address>::1</ip-address>
       </interface>
     </interfaces>

Благодарности

Этот документ является результатом многочисленных обсуждений, тянувшихся с 2010 года. Проблемы исходной модели хранилищ данных были рассмотрены в NETMOD-Operational] [With-config-state] [OpState-Reqs] [OpState-Enhance] [OpState-Modeling], а также [RFC6244]. Перечисленные ниже люди были авторами этих работ или внесли какой-либо иной вклад в создание этого документа.

Работа Juergen Schoenwaelder частично финансировалась в рамках Flamingo — проекта Network of Excellence (ICT-318488), поддерживаемого Европейской комиссией про программе Seventh Framework.

Адреса авторов

Martin Bjorklund

Tail-f Systems

Email: mbj@tail-f.com

Juergen Schoenwaelder

Jacobs University

Email: j.schoenwaelder@jacobs-university.de

Phil Shafer

Juniper Networks

Email: phil@juniper.net

Kent Watsen

Juniper Networks

Email: kwatsen@juniper.net

Robert Wilton

Cisco Systems

Email: rwilton@cisco.com


Перевод на русский язык

Николай Малых

nmalykh@protokols.ru

1Network Configuration Protocol — протокол настройки сети.

2Internet Engineering Task Force — комиссия по решению инженерных задач Internet.

3Internet Engineering Steering Group — комиссия по инженерным разработкам Internet.

4XML Path Language — язык путей XML.

5Forwarding and Control Element Separation — разделение элементов пересылки и управления.

6Field Replaceable Unit — заменяемый в процессе работы блок.

Рубрика: RFC | Комментарии к записи RFC 8342 Network Management Datastore Architecture (NMDA) отключены

RFC 8344 A YANG Data Model for IP Management

Internet Engineering Task Force (IETF)                      M. Bjorklund
Request for Comments: 8344                                Tail-f Systems
Obsoletes: 7277                                               March 2018
Category: Standards Track
ISSN: 2070-1721

Модель данных YANG для управления IP

A YANG Data Model for IP Management

PDF

Аннотация

Этот документ определяет модель данных YANG для управления реализациями IP. Модель включает данные конфигурации и состояния системы.

Модель данных YANG в этом документе соответствует архитектуре хранилища данных сетевого управления NMDA1, определенной в RFC 8342.

Документ отменяет действие RFC 7277.

Статус документа

Документ относится к категории Internet Standards Track.

Документ является результатом работы IETF2 и представляет согласованный взгляд сообщества IETF. Документ прошёл открытое обсуждение и был одобрен для публикации IESG3. Не все одобренные IESG документы претендуют на статус Internet Standard (см. раздел 2 в RFC 7841).

Информацию о текущем статусе документа, ошибках и способах обратной связи можно найти по ссылке https://www.rfc-editor.org/info/rfc8344.

Авторские права

Авторские права (Copyright (c) 2018) принадлежат IETF Trust и лицам, указанным в качестве авторов документа. Все права защищены.

К документу применимы права и ограничения, указанные в BCP 78 и IETF Trust Legal Provisions и относящиеся к документам IETF (http://trustee.ietf.org/license-info), на момент публикации данного документа. Прочтите упомянутые документы внимательно. Фрагменты программного кода, включённые в этот документ, распространяются в соответствии с упрощённой лицензией BSD, как указано в параграфе 4.e документа IETF Trust Legal Provisions, без каких-либо гарантий (как указано в Simplified BSD License).

1. Введение

Этот документ определяет модель данных YANG [RFC7950] для управления реализациями IP.

Модель данных охватывает конфигурацию параметров IPv4 и IPv6 на уровне интерфейсов, а также отображение адресов IP на адреса канального уровня. Модель также дает информацию об используемых в работе адресах IP и имеющихся отображениях канального уровня. Параметры на уровне интерфейсов добавлены путем дополнения (augmentation) модели данных интерфейса, определенной в [RFC8343].

Эта версия модели данных IP поддерживает архитектуру хранилищ NMDA [RFC8342].

1.1. Отличия от RFC 7277

Ветви (subtree) ipv4 и ipv6 с узлами данных config false в ветви /interfaces-state/interface отменены. Все узлы данных config false сейчас присутствуют в ветвях ipv4 и ipv6 субдерева /interfaces/interface.

Серверы, не поддерживающие NMDA или желающие работать с клиентами, не поддерживающими NMDA, могут реализовать отмененные ветви ipv4 и ipv6 в субдереве /interfaces-state/interface.

1.2. Терминология

Ключевые слова необходимо (MUST), недопустимо (MUST NOT), требуется (REQUIRED), нужно (SHALL), не следует (SHALL NOT), следует (SHOULD), не нужно (SHOULD NOT), рекомендуется (RECOMMENDED), не рекомендуется (NOT RECOMMENDED), возможно (MAY), необязательно (OPTIONAL) в данном документе интерпретируются в соответствии с BCP 14 [RFC2119] [RFC8174] тогда и только тогда, когда они выделены шрифтом, как показано здесь.

Перечисленные ниже термины определены в [RFC8342] и не определяются здесь заново.

  • client (клиент);

  • server (сервер);

  • configuration (конфигурация);

  • system state (состояние системы);

  • intended configuration (предполагаемая конфигурация);

  • running configuration datastore (хранилище данных рабочей конфигурации);

  • operational state (операционное состояние);

  • operational state datastore (хранилище данных операционного состояния).

Перечисленные ниже термины определены в [RFC7950] и не определяются здесь заново.

  • augment (дополнение, усиление);

  • data model (модель данных);

  • data node (узел данных).

Терминология для описания моделей YANG представлена в [RFC7950].

1.3. Диаграммы деревьев

Диаграммы деревьев, используемыей в этом документе, следуют обозначениям, определенным в [RFC8340].

2. Модель данных IP

Этот документ определяет модуль YANG ietf-ip, который дополняет списки interface, определенные в модуле ietf-interfaces [RFC8343], связанными с IP узлами данных.

Структура узлов данных IP на уровне интерфейса, за исключением отмененных полей данных, приведена ниже.

   module: ietf-ip
     augment /if:interfaces/if:interface:
       +--rw ipv4!
       |  +--rw enabled?      boolean
       |  +--rw forwarding?   boolean
       |  +--rw mtu?          uint16
       |  +--rw address* [ip]
       |  |  +--rw ip               inet:ipv4-address-no-zone
       |  |  +--rw (subnet)
       |  |  |  +--:(prefix-length)
       |  |  |  |  +--rw prefix-length?   uint8
       |  |  |  +--:(netmask)
       |  |  |     +--rw netmask?         yang:dotted-quad
       |  |  |             {ipv4-non-contiguous-netmasks}?
       |  |  +--ro origin?          ip-address-origin
       |  +--rw neighbor* [ip]
       |     +--rw ip                    inet:ipv4-address-no-zone
       |     +--rw link-layer-address    yang:phys-address
       |     +--ro origin?               neighbor-origin
       +--rw ipv6!
          +--rw enabled?                     boolean
          +--rw forwarding?                  boolean
          +--rw mtu?                         uint32
          +--rw address* [ip]
          |  +--rw ip               inet:ipv6-address-no-zone
          |  +--rw prefix-length    uint8
          |  +--ro origin?          ip-address-origin
          |  +--ro status?          enumeration
          +--rw neighbor* [ip]
          |  +--rw ip                    inet:ipv6-address-no-zone
          |  +--rw link-layer-address    yang:phys-address
          |  +--ro origin?               neighbor-origin
          |  +--ro is-router?            empty
          |  +--ro state?                enumeration
          +--rw dup-addr-detect-transmits?   uint32
          +--rw autoconf
             +--rw create-global-addresses?        boolean
             +--rw create-temporary-addresses?     boolean
             |       {ipv6-privacy-autoconf}?
             +--rw temporary-valid-lifetime?       uint32
             |       {ipv6-privacy-autoconf}?
             +--rw temporary-preferred-lifetime?   uint32
                     {ipv6-privacy-autoconf}?

Модель определяет для интерфейса два контейнера — ipv4 и ipv6, представляющие семейства адресов IPv4 и IPv6. В каждом контейнере имеется лист enabled, который показывает разрешено ли семейство адресов на данном интерфейсе, и лист forwarding, показывающий разрешена ли пересылка пакетов IP данного семейства на этом интерфейсе. В каждом контейнере имеется также список адресов и список отображений адресов IP на адреса канального уровня.

3. Связь с IP-MIB

Если устройство реализует IP-MIB [RFC4293], каждая запись в списках ipv4/address и ipv6/address отобрахается в один из объектов ipAddressEntry, где ipAddressIfIndex указывает address в объеке для интерфейса.

IP-MIB определяет объекты для управления сообщениями IPv6 Router Advertisement. Соответствующие узла данных YANG определены в [RFC8022].

Записи ipv4/neighbor и ipv6/neighbor отображаются на ipNetToPhysicalTable.

Ниже приведена таблица соответствия узлов данных YANG объектам IP-MIB.

Узлы данных YANG для интерфейса и связанные объекты IP-MIB.

Узел данных YANG в /if:interfaces/if:interface

Объект IP-MIB

ipv4

ipv4InterfaceEnableStatus

ipv4/enabled

ipv4InterfaceEnableStatus

ipv4/address

ipAddressEntry

ipv4/address/ip

ipAddressAddrType

ipAddressAddr

ipv4/neighbor

ipNetToPhysicalEntry

ipv4/neighbor/ip

ipNetToPhysicalNetAddressType

ipNetToPhysicalNetAddress

ipv4/neighbor/link-layer-address

ipNetToPhysicalPhysAddress

ipv4/neighbor/origin

ipNetToPhysicalType

ipv6

ipv6InterfaceEnableStatus

ipv6/enabled

ipv6InterfaceEnableStatus

ipv6/forwarding

ipv6InterfaceForwarding

ipv6/address

ipAddressEntry

ipv6/address/ip

ipAddressAddrType

ipAddressAddr

ipv4/address/origin

ipAddressOrigin

ipv6/address/status

ipAddressStatus

ipv6/neighbor

ipNetToPhysicalEntry

ipv6/neighbor/ip

ipNetToPhysicalNetAddressType

ipNetToPhysicalNetAddress

ipv6/neighbor/link-layer-address

ipNetToPhysicalPhysAddress

ipv6/neighbor/origin

ipNetToPhysicalType

ipv6/neighbor/state

ipNetToPhysicalState

4. Модуль YANG для управления IP

Этот модуль импортирует определения типов (typedef) из [RFC6991] и [RFC8343], а они ссылаются на [RFC791], [RFC826], [RFC4861], [RFC4862], [RFC4941], [RFC7217] и [RFC8200].

   <CODE BEGINS> file "ietf-ip@2018-02-22.yang"
   module ietf-ip {
     yang-version 1.1;
     namespace "urn:ietf:params:xml:ns:yang:ietf-ip";
     prefix ip;

     import ietf-interfaces {
       prefix if;
     }
     import ietf-inet-types {
       prefix inet;
     }
     import ietf-yang-types {
       prefix yang;
     }

     organization
       "IETF NETMOD (Network Modeling) Working Group";

     contact
       "WG Web:   <https://datatracker.ietf.org/wg/netmod/> 
        WG List:  <mailto:netmod@ietf.org> 

        Editor:   Martin Bjorklund
                  <mailto:mbj@tail-f.com>"; 
     description
       "Этот модуль содержит набор определений YANG для управления
        реализациями IP.

        Авторские права (Copyright (c) 2018) принадлежат IETF Trust 
        и лицам, указанным как авторы кода. Все права защищены.

        Распространение и использование в исходной и двоичной форме
        с изменениями или без них разрешается в соответствии с условиями,
        указанными в упрощённой лицензии BSD, изложенной в разделе 4.c
        Правового положения IETF Trust применительно к документам IETF
        (http://trustee.ietf.org/license-info). 

        Эта версия модуля YANG является частью RFC 8344, где
        правовые аспекты выражены более полно.";

     revision 2018-02-22 {
       description
         "Обновление для поддержки NMDA.";
       reference
         "RFC 8344: A YANG Data Model for IP Management";
     }

     revision 2014-06-16 {
       description
         "Исходный выпуск.";
       reference
         "RFC 7277: A YANG Data Model for IP Management";
     }

     /*
      * Функции
      */

     feature ipv4-non-contiguous-netmasks {
       description
         "Указывает поддержку масок подсетей с разрывами.";
     }

     feature ipv6-privacy-autoconf {
       description
         "Указывает поддержку расширений приватности для автоматической
          настройки IPv6 без поддержки состояний.";
       reference
         "RFC 4941: Privacy Extensions for Stateless Address
                    Autoconfiguration in IPv6";
     }

 
    /*
      * Определения типов
      */

     typedef ip-address-origin {
       type enumeration {
         enum other {
           description
             "Ничего из перечисленного ниже.";
         }
         enum static {
           description
             "Указывает, что адрес настроен статически, например с 
              помощью NETCONF или командного интерфейса.";
         }
         enum dhcp {
           description
             "Указывает, что адрес выделен системе сервером DHCP.";
         }
         enum link-layer {
           description
             "Указывает адрес, созданный автоматической настройкой IPv6
              без поддержки состояния, который включает адрес link-layer
              в идентификатор интерфейса.";
         }
         enum random {
           description
             "Указывает, что адрес выбран системой случайно, например,
              временный адрес IPv4 из сети 169.254/16, как описано в
              RFC 4941, или семантически «непрозрачный» адрес, как
              описано в RFC 7217.";
           reference
             "RFC 4941: Privacy Extensions for Stateless Address
                        Autoconfiguration in IPv6
              RFC 7217: A Method for Generating Semantically Opaque
                        Interface Identifiers with IPv6 Stateless
                        Address Autoconfiguration (SLAAC)";
         }
       }
       description
         "Источник адреса.";
     }

     typedef neighbor-origin {
       type enumeration {
         enum other {
           description
             "Ничего из указанного ниже.";
         }
         enum static {
           description
             "Указывает статически заданное отображение, например, с
              помощью NETCONF или командного интерфейса.";
         }

         enum dynamic {
           description
             "Указывает, что отображение распознано динамически, 
              например, по протоколу IPv4 ARP или IPv6 Neighbor
              Discovery.";
         }
       }
       description
         "Источник записи о соседе.";
     }


     /*
      * Узлы данных
      */

     augment "/if:interfaces/if:interface" {
       description
         "IP-параметры интерфейсов. Если интерфейс не способен
          поддерживать IP, серверу недопустимо разрешать клиенту
          настройку этих параметров.";

       container ipv4 {
         presence
           "Разрешает IPv4, если лист enabled (по умолчанию true)
            не имеет значения false";
         description
           "Параметры для семейства адресов IPv4.";

         leaf enabled {
           type boolean;
           default true;
           description
             "Управляет поддержкой IPv4 на этом интерфейсе. Если
              IPv4 разрешён, интерфейс подключается к стеку IPv4 и
              может передавать и принимать пакеты IPv4.";
         }
         leaf forwarding {
           type boolean;
           default false;
           description
             "Управляет пересылкой пакетов IPv4 с дейтаграммами, by,
              принятыми интерфейсом, но не адресованными ему. 
              Маршрутизаторы IPv4 пересылают дейтаграммы, хосты не
              пересылают (за исключением source-route через хост).";
         }
         leaf mtu {
           type uint16 {
             range "68..max";
           }
           units "octets";
           description
             "Размер (в октетах) максимального пакета IPv4, который
              интерфейс будет передавать и принимать.

              Сервер может ограничивать разрешённые значения для этого
              листа в зависимости от типа интерфейса.

              Если лист не настроен, применяемое значение MTU зависит
              от типа интерфейса.";
           reference
             "RFC 791: Internet Protocol";
         }
         list address {
           key "ip";
           description
             "Список адресов IPv4 на интерфейсе.";
           leaf ip {
             type inet:ipv4-address-no-zone;
             description
               "Адрес IPv4 на интерфейсе.";
           }
           choice subnet {
             mandatory true;
             description
               "Подсеть можно указать размером префикса или (если сервер
                поддерживает маски с разрывом) листом netmask.";
             leaf prefix-length {
               type uint8 {
                 range "0..32";
               }
               description
                 "Размер префикса подсети.";
             }
             leaf netmask {
               if-feature ipv4-non-contiguous-netmasks;
               type yang:dotted-quad;
               description
                 "Подсеть задаётся маской.";
             }
           }
           leaf origin {
             type ip-address-origin;
             config false;
             description
               "Источник адреса.";
           }
         }
         list neighbor {
           key "ip";
           description
             "Список сопоставлений адресов IPv4 с адресами канального
              уровня. 

              Записи этого списка в предполагаемой конфигурации 
              служат в качестве статических записей кэша ARP.
              В рабочем состоянии этот список представляет кэш ARP.";
           reference
             "RFC 826: An Ethernet Address Resolution Protocol";

           leaf ip {
             type inet:ipv4-address-no-zone;
             description
               "Адрес IPv4 соседнего узла.";
           }
           leaf link-layer-address {
             type yang:phys-address;
             mandatory true;
             description
               "Адрес соседа на канальном уровне.";
           }
           leaf origin {
             type neighbor-origin;
             config false;
             description
               "Источник этой записи о соседе.";
           }
         }
       }

       container ipv6 {
         presence
           "Разрешает IPv6, если лист enabled (по умолчанию true)
            не имеет значения false";
         description
           "Параметры для семейства адресов IPv6.";

         leaf enabled {
           type boolean;
           default true;
           description
             "Управляет поддержкой IPv6 на этом интерфейсе. Если
              IPv6 разрешён, интерфейс подключается к стеку IPv4 и
              может передавать и принимать пакеты IPv6.";
         }
         leaf forwarding {
           type boolean;
           default false;
           description
             "Управляет пересылкой пакетов IPv6 с дейтаграммами, by,
              принятыми интерфейсом, но не адресованными ему. 
              Маршрутизаторы IPv6 пересылают дейтаграммы, хосты не
              пересылают (за исключением source-route через хост).";
           reference
             "RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
                        Section 6.2.1, IsRouter";
         }
         leaf mtu {
           type uint32 {
             range "1280..max";
           }
           units "octets";
           description
             "Размер (в октетах) максимального пакета IPv6, который
              интерфейс будет передавать и принимать.

              Сервер может ограничивать разрешённые значения для этого
              листа в зависимости от типа интерфейса.

              Если лист не настроен, применяемое значение MTU зависит
              от типа интерфейса.";
           reference
             "RFC 8200: Internet Protocol, Version 6 (IPv6)
                        Specification
                        Section 5";
         }

         list address {
           key "ip";
           description
             "Список адресов IPv6 на интерфейсе.";

           leaf ip {
             type inet:ipv6-address-no-zone;
             description
               "Адрес IPv6 на интерфейсе.";
           }
           leaf prefix-length {
             type uint8 {
               range "0..128";
             }
             mandatory true;
             description
               "Размер префикса подсети.";
           }
           leaf origin {
             type ip-address-origin;
             config false;
             description
               "Источник адреса.";
           }
           leaf status {
             type enumeration {
               enum preferred {
                 description
                   "Это действительный адрес, который может указывать
                    отправителя или получателя пакета.";
               }
               enum deprecated {
                 description
                   "Это действительный, но устаревший адрес, который не
                    следует применять для отправителя в новых пакетах,
                    но следует корректно обрабатывать в получаемых.";
               }
               enum invalid {
                 description
                   "Это недействительный адрес и его не следует 
                    указывать в поле отправителя или получателя пакета";
               }

               enum inaccessible {
                 description
                   "Адрес недоступен, поскольку интерфейс, в которым он
                    связан, не работает.";
               }
               enum unknown {
                 description
                   "Статус невозможно определить по какой-то причине.";
               }

               enum tentative {
                 description
                   "Уникальность адреса на канале проверяется. Адреса с
                    таким статусом не следует применять для общих
                    коммуникаций, оставляя его лишь для проверки
                    уникальности адреса.";
               }
               enum duplicate {
                 description
                   "Адрес сочтён неуникальным на канале и его 
                    недопустимо использовать.";
               }
               enum optimistic {
                 description
                   "Адрес доступен для использования с учётом 
                    ограничений, уникальность на канале проверяется.";
               }
             }
             config false;
             description
               "Статус адреса. Большинство состояний соответствует
                значениям из IPv6 Stateless Address Autoconfiguration.";
             reference
               "RFC 4293: Management Information Base for the
                          Internet Protocol (IP)
                          - IpAddressStatusTC
                RFC 4862: IPv6 Stateless Address Autoconfiguration";
           }
         }

         list neighbor {
           key "ip";
           description
             "Список сопоставлений адресов IPv6 с адресами канального
              уровня. 
              Записи этого списка в предполагаемой конфигурации 
              служат в качестве статических записей кэша соседей.
              В рабочем состоянии список представляет кэш соседей.";
           reference
             "RFC 4861: Neighbor Discovery for IP version 6 (IPv6)";

           leaf ip {
             type inet:ipv6-address-no-zone;
             description
               "Адрес IPv6 соседнего узла.";
           }
           leaf link-layer-address {
             type yang:phys-address;
             mandatory true;
             description
               "Адрес соседнего узла на канальном уровне.
                В рабочем состоянии при state incomplete этот лист
                не создается.";
           }
           leaf origin {
             type neighbor-origin;
             config false;
             description
               "Источник записи о соседе.";
           }
           leaf is-router {
             type empty;
             config false;
             description
               "Указывает, что сосед служит маршрутизатором.";
           }

           leaf state {
             type enumeration {
               enum incomplete {
                 description
                   "Распознавание адреса не завершено и адрес канального
                    уровня для соседа ещё не определён.";
               }
               enum reachable {
                 description
                   "Грубо говоря, сосед был доступен недавно 
                    (десятки секунд назад).";
               }
               enum stale {
                 description
                   "О доступности соседа больше нет сведений, но пока
                    трафик передаётся ему, не следует проверять его
                    доступность.";
               }
               enum delay {
                 description
                   "О доступности соседа больше нет сведений и трафик
                    недавно передавался ему. Проверку его доступности
                    тестовыми пакетами следует отложить на короткое
                    время, чтобы протоколы верхних уровней могли 
                    предоставить подтверждение доступности.";
               }
               enum probe {
                 description
                   "О доступности соседа больше нет сведений и для её 
                    проверки передаются пакеты Neighbor Solicitation.";
               }
             }
             config false;
             description
               "Состояние Neighbor Unreachability Detection для записи";
             reference
               "RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
                          Section 7.3.2";
           }
         }

         leaf dup-addr-detect-transmits {
           type uint32;
           default 1;
           description
             "Число последовательных сообщений Neighbor Solicitation,
              переданных в процессе Duplicate Address Detection на
              предварительный адрес. Нулевое значение указывает, что
              Duplicate Address Detection не выполняется для 
              предварительных адресов. Значение 1 указывает одиночную
              отправку без повторов.";
           reference
             "RFC 4862: IPv6 Stateless Address Autoconfiguration";
         }
         container autoconf {
           description
             "Параметры управления автоматической настройкой адресов
              IPv6 в соответствии с RFC 4862.";
           reference
             "RFC 4862: IPv6 Stateless Address Autoconfiguration";

           leaf create-global-addresses {
             type boolean;
             default true;
             description
               "При значении true хост создаёт глобальные адреса в
                соответствии с RFC 4862.";
             reference
               "RFC 4862: IPv6 Stateless Address Autoconfiguration
                          Section 5.5";
           }
           leaf create-temporary-addresses {
             if-feature ipv6-privacy-autoconf;
             type boolean;
             default false;
             description
               "При значении true хост создаёт временные адреса в
                соответствии с RFC 4941.";
             reference
               "RFC 4941: Privacy Extensions for Stateless Address
                          Autoconfiguration in IPv6";
           }
           leaf temporary-valid-lifetime {
             if-feature ipv6-privacy-autoconf;
             type uint32;
             units "seconds";
             default 604800;
             description
               "Срок действия временных адресов.";
             reference
               "RFC 4941: Privacy Extensions for Stateless Address
                          Autoconfiguration in IPv6
                          - TEMP_VALID_LIFETIME";
           }
           leaf temporary-preferred-lifetime {
             if-feature ipv6-privacy-autoconf;
             type uint32;
             units "seconds";
             default 86400;
             description
               "Срок предпочтения временных адресов.";
             reference
               "RFC 4941: Privacy Extensions for Stateless Address
                          Autoconfiguration in IPv6
                          - TEMP_PREFERRED_LIFETIME";
           }
         }
       }
     }

     /*
      * Унаследованные узлы данных операционных состояний
      */

     augment "/if:interfaces-state/if:interface" {
       status deprecated;
       description
         "Узлы данных рабочего состояния IP на интерфейсах.";

       container ipv4 {
         presence
           "Присутствует при включении IPv4 на интерфейсе.";
         config false;
         status deprecated;
         description
           "Зависящие от интерфейса параметры для семейства IPv4.";

         leaf forwarding {
           type boolean;
           status deprecated;
           description
             "Указывает, включена ли на интерфейсе пересылка IPv4.";
         }
         leaf mtu {
           type uint16 {
             range "68..max";
           }
           units "octets";
           status deprecated;
           description
             "Максимальный размер пакета IPv4, который интерфейс может
              передать и принять (в октетах).";
           reference
             "RFC 791: Internet Protocol";
         }

         list address {
           key "ip";
           status deprecated;
           description
             "Список адресов IPv4 на интерфейсе.";

           leaf ip {
             type inet:ipv4-address-no-zone;
             status deprecated;
             description
               "Адрес IPv4 на интерфейсе.";
           }

           choice subnet {
             status deprecated;
             description
               "Подсеть можно указать размером префикса или (если сервер
                поддерживает маски с разрывом) листом netmask.";
             leaf prefix-length {
               type uint8 {
                 range "0..32";
               }
               status deprecated;
               description
                 "Размер префикса подсети.";
             }
             leaf netmask {
               if-feature ipv4-non-contiguous-netmasks;
               type yang:dotted-quad;
               status deprecated;
               description
                 "Подсеть задаётся как netmask.";
             }
           }
           leaf origin {
             type ip-address-origin;
             status deprecated;
             description
               "Источник данного адреса.";
           }
         }
         list neighbor {
           key "ip";
           status deprecated;
           description
             "Список сопоставлений адресов IPv4 с адресами канального 
              уровня. Этот список представляет ARP Cache.";
           reference
             "RFC 826: An Ethernet Address Resolution Protocol";

           leaf ip {
             type inet:ipv4-address-no-zone;
             status deprecated;
             description
               "Адрес IPv4 у соседнего узла.";
           }
           leaf link-layer-address {
             type yang:phys-address;
             status deprecated;
             description
               "Адрес канального уровня у соседнего узла.";
           }
           leaf origin {
             type neighbor-origin;
             status deprecated;
             description
               "Источник этой записи о соседе.";
           }
         }
       }

       container ipv6 {
         presence
           "Присутствует при включении IPv6 на интерфейсе.";
         config false;
         status deprecated;
         description
           "Параметры для семейства адресов IPv6.";

         leaf forwarding {
           type boolean;
           default false;
           status deprecated;
           description
             "Указывает, включена ли на интерфейсе пересылка IPv6.";
           reference
             "RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
                        Section 6.2.1, IsRouter";
         }
         leaf mtu {
           type uint32 {
             range "1280..max";
           }
           units "octets";
           status deprecated;
           description
             "Максимальный размер пакета IPv6, который интерфейс может
              передать и принять (в октетах).";
           reference
             "RFC 8200: Internet Protocol, Version 6 (IPv6)
                        Specification
                        Section 5";
         }

         list address {
           key "ip";
           status deprecated;
           description
             "Список адресов IPv6 на интерфейсе.";

           leaf ip {
             type inet:ipv6-address-no-zone;
             status deprecated;
             description
               "Адрес IPv6 на интерфейсе.";
           }
           leaf prefix-length {
             type uint8 {
               range "0..128";
             }
             mandatory true;
             status deprecated;
             description
               "Размер префикса подсети.";
           }
           leaf origin {
             type ip-address-origin;
             status deprecated;
             description
               "Источник этого адреса.";
           }
           leaf status {
             type enumeration {
               enum preferred {
                 description
                   "Это действительный адрес, который может указывать
                    отправителя или получателя пакета.";
               }
               enum deprecated {
                 description
                   "Это действительный, но устаревший адрес, который не
                    следует применять для отправителя в новых пакетах,
                    но следует корректно обрабатывать в получаемых.";
               }
               enum invalid {
                 description
                   "Это недействительный адрес и его не следует 
                    указывать в поле отправителя или получателя пакета";
               }

               enum inaccessible {
                 description
                   "Адрес недоступен, поскольку интерфейс, в которым он
                    связан, не работает.";
               }
               enum unknown {
                 description
                   "Статус невозможно определить по какой-то причине.";
               }
               enum tentative {
                 description
                   "Уникальность адреса на канале проверяется. Адреса с
                    таким статусом не следует применять для общих
                    коммуникаций, оставляя его лишь для проверки
                    уникальности адреса.";
               }
               enum duplicate {
                 description
                   "Адрес сочтён неуникальным на канале и его 
                    недопустимо использовать.";
               }
               enum optimistic {
                 description
                   "Адрес доступен для использования с учётом 
                    ограничений, уникальность на канале проверяется.";
               }
             }
             status deprecated;
             description
               "Статус адреса. Большинство состояний соответствует
                протоколу IPv6 Stateless Address Autoconfiguration.";
             reference
               "RFC 4293: Management Information Base for the
                          Internet Protocol (IP)
                          - IpAddressStatusTC
                RFC 4862: IPv6 Stateless Address Autoconfiguration";
           }
         }

         list neighbor {
           key "ip";
           status deprecated;
           description
             "Список сопоставлений адресов IPv4 с адресами канального 
              уровня. Этот список представляет Neighbor Cache.";
           reference
             "RFC 4861: Neighbor Discovery for IP version 6 (IPv6)";

           leaf ip {
             type inet:ipv6-address-no-zone;
             status deprecated;
             description
               "Адрес IPv6 у соседнего узла.";
           }
           leaf link-layer-address {
             type yang:phys-address;
             status deprecated;
             description
               "Адрес канального уровня у соседнего узла.";
           }
           leaf origin {
             type neighbor-origin;
             status deprecated;
             description
               "Источник этой записи о соседе.";
           }
           leaf is-router {
             type empty;
             status deprecated;
             description
               "Указывает, что сосед служит маршрутизатором.";
           }
           leaf state {
             type enumeration {
               enum incomplete {
                 description
                   "Распознавание адреса не завершено и адрес канального
                    уровня для соседа ещё не определён.";
               }
               enum reachable {
                 description
                   "Грубо говоря, сосед был доступен недавно 
                    (десятки секунд назад).";
               }

               enum stale {
                 description
                   "О доступности соседа больше нет сведений, но пока
                    трафик передаётся ему, не следует проверять его
                    доступность.";
               }
               enum delay {
                 description
                   "О доступности соседа больше нет сведений и трафик
                    недавно передавался ему. Проверку его доступности
                    тестовыми пакетами следует отложить на короткое
                    время, чтобы протоколы верхних уровней могли 
                    предоставить подтверждение доступности.";
               }
               enum probe {
                 description
                   "О доступности соседа больше нет сведений и для её 
                    проверки передаются пакеты Neighbor Solicitation.";
               }
             }
             status deprecated;
             description
               "Состояние Neighbor Unreachability Detection для записи";
             reference
               "RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
                          Section 7.3.2";
           }
         }
       }
     }
   }
   <CODE ENDS>

5. Взаимодействие с IANA

Этот документ регистрирует URI в реестре IETF XML Registry [RFC3688]. В соответствии с форматом RFC 3688 выполнены перечисленные ниже регистрации.

      URI: urn:ietf:params:xml:ns:yang:ietf-ip
      Registrant Contact: The NETMOD WG of the IETF.
      XML: N/A; the requested URI is an XML namespace.

Этот документ регистрирует модуль YANG в реестре YANG Module Names [RFC6020].

      Name:         ietf-ip
      Namespace:    urn:ietf:params:xml:ns:yang:ietf-ip
      Prefix:       ip
      Reference:    RFC 8344

6. Вопросы безопасности

Описанный в этом документе модуль YANG определяет схему для данных, доступ к которым выполняется с помощью протоколов сетевого управления типа NETCONF [RFC6241] или RESTCONF [RFC8040]. Нижним уровнем NETCONF является защищённый транспортный уровень с обязательной реализацией защищённого транспорта SSH4 [RFC6242]. Нижним уровнем RESTCONF является HTTPS с обязательной для реализацией транспорта TLS [RFC5246].

Модель управления доступом NETCONF [RFC8341] обеспечивает меры по ограничению доступа для отдельных пользователей NETCONF или RESTCONF предопределенным подмножеством всех доступных операций и содержимого NETCONF или RESTCONF.

Многие модели данных, определённые в этом модуле YANG обеспечивают возможность записи, создания и удаления (т. е. по умолчанию установлено config true). Эти узлы данных могут содержать конфиденциальную (sensitive) информацию , а также быть уязвимыми в некоторых сетевых средах. Операции записи (например, edit-config) для таких узлов без подобающей защиты могут оказывать нежелательное воздействие на работу сети. Ниже перечислены ветви (subtree) и узлы данных, которые могут включать конфиденциальную информацию или уязвимости.

ipv4/enabled и ipv6/enabled

Эти листья используются для включения или отключения IPv4 и IPv6 на конкретных интерфейсах. Включив протокол на интерфейсе, атакующий может получить возможность создания незащищённого пути к узлу (или через него, если включена маршрутизация). Отключив протокол на интерфейсе, атакующий сможет вынудить к маршрутизации пакетов через другой интерфейс или заблокировать доступ к части или всей сети по этому протоколу.

ipv4/address и ipv6/address

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

ipv4/forwarding и ipv6/forwarding

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

ipv6/autoconf

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

ipv4/mtu и ipv6/mtu

Установка для этих листьев очень малых значений может существенно замедлить работу интерфейсов.

7. Литература

7.1. Нормативные документы

[RFC791] Postel, J., «Internet Protocol», STD 5, RFC 791, DOI 10.17487/RFC0791, September 1981, <https://www.rfc-editor.org/info/rfc791>.

[RFC2119] Bradner, S., «Key words for use in RFCs to Indicate Requirement Levels», BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, <https://www.rfc-editor.org/info/rfc2119>.

[RFC3688] Mealling, M., «The IETF XML Registry», BCP 81, RFC 3688, DOI 10.17487/RFC3688, January 2004, <https://www.rfc-editor.org/info/rfc3688>.

[RFC4861] Narten, T., Nordmark, E., Simpson, W., and H. Soliman, «Neighbor Discovery for IP version 6 (IPv6)», RFC 4861, DOI 10.17487/RFC4861, September 2007, <https://www.rfc-editor.org/info/rfc4861>.

[RFC4862] Thomson, S., Narten, T., and T. Jinmei, «IPv6 Stateless Address Autoconfiguration», RFC 4862, DOI 10.17487/RFC4862, September 2007, <https://www.rfc-editor.org/info/rfc4862>.

[RFC4941] Narten, T., Draves, R., and S. Krishnan, «Privacy Extensions for Stateless Address Autoconfiguration in IPv6», RFC 4941, DOI 10.17487/RFC4941, September 2007, <https://www.rfc-editor.org/info/rfc4941>.

[RFC5246] Dierks, T. and E. Rescorla, «The Transport Layer Security (TLS) Protocol Version 1.2», RFC 5246, DOI 10.17487/RFC5246, August 2008, <https://www.rfc-editor.org/info/rfc5246>.

[RFC6020] Bjorklund, M., Ed., «YANG — A Data Modeling Language for the Network Configuration Protocol (NETCONF)», RFC 6020, DOI 10.17487/RFC6020, October 2010, <https://www.rfc-editor.org/info/rfc6020>.

[RFC6241] Enns, R., Ed., Bjorklund, M., Ed., Schoenwaelder, J., Ed., and A. Bierman, Ed., «Network Configuration Protocol (NETCONF)», RFC 6241, DOI 10.17487/RFC6241, June 2011, <https://www.rfc-editor.org/info/rfc6241>.

[RFC6242] Wasserman, M., «Using the NETCONF Protocol over Secure Shell (SSH)», RFC 6242, DOI 10.17487/RFC6242, June 2011, <https://www.rfc-editor.org/info/rfc6242>.

[RFC6991] Schoenwaelder, J., Ed., «Common YANG Data Types», RFC 6991, DOI 10.17487/RFC6991, July 2013, <https://www.rfc-editor.org/info/rfc6991>.

[RFC7950] Bjorklund, M., Ed., «The YANG 1.1 Data Modeling Language», RFC 7950, DOI 10.17487/RFC7950, August 2016, <https://www.rfc-editor.org/info/rfc7950>.

[RFC8040] Bierman, A., Bjorklund, M., and K. Watsen, «RESTCONF Protocol», RFC 8040, DOI 10.17487/RFC8040, January 2017, <https://www.rfc-editor.org/info/rfc8040>.

[RFC8174] Leiba, B., «Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words», BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017, <https://www.rfc-editor.org/info/rfc8174>.

[RFC8200] Deering, S. and R. Hinden, «Internet Protocol, Version 6 (IPv6) Specification», STD 86, RFC 8200, DOI 10.17487/RFC8200, July 2017, <https://www.rfc-editor.org/info/rfc8200>.

[RFC8341] Bierman, A. and M. Bjorklund, «Network Configuration Access Control Model», STD 91, RFC 8341, DOI 10.17487/RFC8341, March 2018, <https://www.rfc-editor.org/info/rfc8341>.

[RFC8342] Bjorklund, M., Schoenwaelder, J., Shafer, P., Watsen, K., and R. Wilton, «Network Management Datastore Architecture (NMDA)», RFC 8342, DOI 10.17487/RFC8342, March 2018, <https://www.rfc-editor.org/info/rfc8342>.

[RFC8343] Bjorklund, M., «A YANG Data Model for Interface Management», RFC 8343, DOI 10.17487/RFC8343, March 2018, <https://www.rfc-editor.org/info/rfc8343>.

[W3C.REC-xml-20081126] Bray, T., Paoli, J., Sperberg-McQueen, M., Maler, E., and F. Yergeau, «Extensible Markup Language (XML) 1.0 (Fifth Edition)», World Wide Web Consortium Recommendation REC-xml-20081126, November 2008, <https://www.w3.org/TR/2008/REC-xml-20081126>.

7.2. Дополнительная литература

[RFC826] Plummer, D., «An Ethernet Address Resolution Protocol: Or Converting Network Protocol Addresses to 48.bit Ethernet Address for Transmission on Ethernet Hardware», STD 37, RFC 826, DOI 10.17487/RFC0826, November 1982, <https://www.rfc-editor.org/info/rfc826>.

[RFC4293] Routhier, S., Ed., «Management Information Base for the Internet Protocol (IP)», RFC 4293, DOI 10.17487/RFC4293, April 2006, <https://www.rfc-editor.org/info/rfc4293>.

[RFC7217] Gont, F., «A Method for Generating Semantically Opaque Interface Identifiers with IPv6 Stateless Address Autoconfiguration (SLAAC)», RFC 7217, DOI 10.17487/RFC7217, April 2014, <https://www.rfc-editor.org/info/rfc7217>.

[RFC8022] Lhotka, L. and A. Lindem, «A YANG Data Model for Routing Management», RFC 8022, DOI 10.17487/RFC8022, November 2016, <https://www.rfc-editor.org/info/rfc8022>.

[RFC8340] Bjorklund, M. and L. Berger, Ed., «YANG Tree Diagrams», BCP 215, RFC 8340, DOI 10.17487/RFC8340, March 2018, <https://www.rfc-editor.org/info/rfc8340>.

Приложение A. Пример отклика NETCONF <get-config>

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

Фрагменты XML [W3C.REC-xml-20081126] в этом и следующем приложении даны лишь в качестве примеров.

   <rpc-reply
       xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"
       message-id="101">
     <data>
       <interfaces
           xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"
           xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type">
         <interface>
           <name>eth0</name>
           <type>ianaift:ethernetCsmacd</type>
           <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
             <address>
               <ip>192.0.2.1</ip>
               <prefix-length>24</prefix-length>
             </address>
           </ipv4>
           <ipv6 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
             <mtu>1280</mtu>
             <address>
               <ip>2001:db8::10</ip>
               <prefix-length>32</prefix-length>
             </address>
             <dup-addr-detect-transmits>0</dup-addr-detect-transmits>
           </ipv6>
         </interface>
       </interfaces>
     </data>
   </rpc-reply>

Приложение B. Пример отклика NETCONF <get-data>

В этом приложении дан пример отклика на запрос NETCONF <get-data> для хранилища состояния на устройстве, поддерживающем описанную в этом документе модель данных.

В примере используется аннотация origin, определенная в модуле ietf-origin [RFC8342].

   <rpc-reply
       xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"
       message-id="101">
     <data xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-datastores">
       <interfaces
           xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"
           xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type"
           xmlns:or="urn:ietf:params:xml:ns:yang:ietf-origin">

         <interface or:origin="or:intended">
           <name>eth0</name>
           <type>ianaift:ethernetCsmacd</type>
           <!-- other parameters from ietf-interfaces omitted -->

           <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
             <enabled or:origin="or:default">true</enabled>
             <forwarding or:origin="or:default">false</forwarding>
             <mtu or:origin="or:system">1500</mtu>
             <address>
               <ip>192.0.2.1</ip>
               <prefix-length>24</prefix-length>
               <origin>static</origin>
             </address>
             <neighbor or:origin="or:learned">
               <ip>192.0.2.2</ip>
               <link-layer-address>
                 00:00:5E:00:53:AB
               </link-layer-address>
             </neighbor>
           </ipv4>
           <ipv6 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
             <enabled or:origin="or:default">true</enabled>
             <forwarding or:origin="or:default">false</forwarding>
             <mtu>1280</mtu>
             <address>
               <ip>2001:db8::10</ip>
               <prefix-length>32</prefix-length>
               <origin>static</origin>
               <status>preferred</status>
             </address>
             <address or:origin="or:learned">
               <ip>2001:db8::1:100</ip>
               <prefix-length>32</prefix-length>
               <origin>dhcp</origin>
               <status>preferred</status>
             </address>
             <dup-addr-detect-transmits>0</dup-addr-detect-transmits>
             <neighbor or:origin="or:learned">
               <ip>2001:db8::1</ip>
               <link-layer-address>
                 00:00:5E:00:53:AB
               </link-layer-address>
               <origin>dynamic</origin>
               <is-router/>
               <state>reachable</state>
             </neighbor>
             <neighbor or:origin="or:learned">
               <ip>2001:db8::4</ip>
               <origin>dynamic</origin>
               <state>incomplete</state>
             </neighbor>
           </ipv6>
         </interface>
       </interfaces>
     </data>
   </rpc-reply>

Благодарности

Автор благодарит Jeffrey Lange, Ladislav Lhotka, Juergen Schoenwaelder и Dave Thaler за их полезные комментарии.

Адрес автора

Martin Bjorklund

Tail-f Systems

Email: mbj@tail-f.com


Перевод на русский язык

Николай Малых

nmalykh@protokols.ru

1Network Management Datastore Architecture.

2Internet Engineering Task Force — комиссия по решению инженерных задач Internet.

3Internet Engineering Steering Group — комиссия по инженерным разработкам Internet.

4Secure Shell — защищённая среда выполнения команд.

Рубрика: RFC | Комментарии к записи RFC 8344 A YANG Data Model for IP Management отключены

RFC 8341 Network Configuration Access Control Model

Internet Engineering Task Force (IETF)                        A. Bierman
Request for Comments: 8341                                     YumaWorks
STD: 91                                                     M. Bjorklund
Obsoletes: 6536                                           Tail-f Systems
Category: Standards Track                                     March 2018
ISSN: 2070-1721

Модель управления доступом NETCONF

Network Configuration Access Control Model

PDF

Аннотация

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

Данный документ отменяет RFC 6536.

Статус документа

Этот документ является проектом стандарта (Internet Standards Track).

Документ является результатом работы IETF2 и представляет собой согласованное мнение сообщества IETF. Документ был вынесен на публичное рассмотрение и одобрен для публикации IESG3. Дополнительная информация о документах Internet Standard представлена в разделе 2 документа RFC 7841.

Информация о текущем статусе этого документа, обнаруженных ошибках и способах обратной связи может быть найдена по ссылке https://www.rfc-editor.org/info/rfc8341.

Авторские права

Авторские права (Copyright (c) 2018) принадлежат IETF Trust и лицам, указанным в качестве авторов документа. Все права защищены.

К документу применимы права и ограничения, указанные в BCP 78 и IETF Trust Legal Provisions и относящиеся к документам IETF (http://trustee.ietf.org/license-info), на момент публикации данного документа. Прочтите упомянутые документы внимательно. Фрагменты программного кода, включённые в этот документ, распространяются в соответствии с упрощённой лицензией BSD, как указано в параграфе 4.e документа IETF Trust Legal Provisions, без каких-либо гарантий (как указано в Simplified BSD License).

1. Введение

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

Существует необходимость интероперабельного управления доступом к выбранным администратором частям содержимого NETCONF и RESTCONF в рамках отдельного сервера.

Этот документ решает вопросы управления доступом к операциям и содержимому протоколов NETCONF [RFC6241] и RESTCONF [RFC8040]. Документ включает три основных раздела.

  1. Цели управления доступом.

  2. Модель управления доступом для NETCONF (NACM).

  3. Модель данных YANG (ietf-netconf-acm.yang).

YANG версии 1.1 [RFC7950] добавляет две новых конструкции, для которых требуется специальный контроль доступа. Оператор action похож на оператор rpc, за исключением того, что он размещается в узле данных. Оператор notification также может размещаться в узле данных.

1.1. Терминология

Ключевые слова необходимо (MUST), недопустимо (MUST NOT), требуется (REQUIRED), нужно (SHALL), не следует (SHALL NOT), следует (SHOULD), не нужно (SHOULD NOT), рекомендуется (RECOMMENDED), не рекомендуется (NOT RECOMMENDED), возможно (MAY), необязательно (OPTIONAL) в данном документе интерпретируются в соответствии с BCP 14 [RFC2119] [RFC8174] тогда и только тогда, когда они выделены шрифтом, как показано здесь.

Приведенные ниже термины определены в [RFC8342] и не переопределяются здесь:

  • datastore — хранилище данных;

  • configuration datastore хранилище конфигурации;

  • conventional configuration datastore традиционное (обычное) хранилище данных конфигурации;

  • candidate configuration datastore хранилище будущей конфигурации, хранилище-кандидат;

  • running configuration datastore хранилище рабочей конфигурации;

  • startup configuration datastore хранилище стартовой конфигурации;

  • operational state datastore хранилище рабочего состояния;

  • client — клиент;

  • server — сервер.

Приведенные ниже термины определены в [RFC6241] и не переопределяются здесь:

  • protocol operation — протокольная операция;

  • session — сессия;

  • user — пользователь.

Приведенные ниже термины определены в [RFC7950] и не переопределяются здесь:

  • action — действие;

  • data node — узел данных;

  • data definition statement — оператор определения данных.

Приведенные ниже термины определены в [RFC8040] и не переопределяются здесь:

  • data resource — ресурс данных;

  • datastore resource — ресурс хранилища данных;

  • operation resource — операционный ресурс;

  • target resource — целевой ресурс.

Приведенный ниже термин определен в [RFC7230] и не переопределяется здесь:

  • request URI — идентификатор запроса.

Ниже приведены определения других используемых в документе терминов.

access control – контроль доступа

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

access control model (ACM) – модель контроля доступа

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

access control rule – правило контроля доступа

Критерий, используемый для решения вопроса о предоставлении доступа к конкретной операции.

access operation – операция доступа

Способ получения запросом доступа к концептуальному объекту (none — нет, read — чтение, create — создание, delete — удаление, update — обновление или execute — исполнение).

data node hierarchy и иерархия узла данных

Иерархия узлов данных, указывающая конкретный узел action или notification в хранилище данных.

recovery session – сеанс восстановления

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

write access – доступ для записи

Общее обозначение операций create, delete и update.

1.2. Отличия от RFC 6536

Процедуры и модель данных NACM были обновлены для поддержки новых возможностей моделирования в версии языка YANG 1.1. Операторы action и notification могут использоваться с узлами данных для определения операций и уведомлений в конкретной модели данных.

Важным применением этих новых операторов YANG является повышение детализации контроля доступа по сравнению с возможностями, предоставляемыми операторами верхнего уровня rpc и notification. Новые операторы action и notification используются внутри узлов данных и доступ к действиям или уведомлениям может быть ограничен для конкретных узлов данных.

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

Было разъяснено поведение доступа к узлу данных при совпадении пути для включения соответствующих нисходящих узлов указанного пути.

Разъяснено поведение в части прав доступа к операции <edit-config> для указания того, что право записи не требуется для узлов данных, которые неявно меняются за счет побочных эффектов (типа вычисления операторов YANG when или неявного удаления при создании узла данных в другой ветви оператора YANG choice).

Раздел «Вопросы безопасности» был обновлен в соответствии с документом «YANG module security guidelines» [YANG-SEC]. Отметим, что модуль YANG в этом документе не определяет новых операций RPC.

2. Цели управления доступом

В этом разделе описаны цели разработки модели управления доступом к NETCONF, представленной в разделе 3.

2.1. Точки управления доступом

NETCONF позволяет разработчикам серверов добавлять свои протокольные операции и язык моделирования данных YANG поддерживает это. Операции могут быть определены в стандартных или фирменных модулях YANG.

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

Эти точки контроля показаны на рисунке 1 и кратко описаны ниже.

Протокольные операции

Разрешение на вызов конкретных операций протокола.

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

Разрешение считывать и/или изменять конкретные узлы данных внутри хранилища.

Уведомления

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

             +-------------+                 +-------------+
запрос       |протокольная |                 |  доступ к   |
клиента -->  |  операция   | ------------->  | узлу данных |
             | разрешена?  | хранилище данных|  разрешен?  |
             +-------------+ или доступ к    +-------------+
                             данным состояния

             +----------------+
             |  уведомление   |
событие -->  |  разрешено?    |
             +----------------+

Рисунок 1.

2.2. Простота

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

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

Контроль доступа должен определяться с помощью небольшого и понятного набора разрешений и при этом должен обеспечивать полное управления доступом к хранилищам данных.

2.3. Процедурный интерфейс

NETCONF использует модель RPC4 и расширяемый набор протокольных операций. Требуется контроль доступа для любой возможной операции протокола.

2.4. Доступ к хранилищу данных

Необходимо контролировать доступ к конкретным узлам и субдеревьям в хранилище данных независимо от протокольных операций (стандартных или фирменных), используемых для доступа к хранилищу.

2.5. Пользователи и группы

Требуется возможность настройки правил доступа для одного пользователя или настраиваемой группы пользователей.

В ACM требуется поддержка концепции административных групп, позволяющей четко различать учетные записи администраторов (root account) и других пользователей с меньшими привилегиями. Администратор должен иметь возможность настройки групп.

Необходима возможность передачи полномочий по сопоставлению пользователей с группами централизованному серверу (например, RADIUS [RFC2865] [RFC5607]). Поскольку проверка подлинности выполняется транспортным уровнем и RADIUS выполняет аутентификацию предоставление полномочий сервису одновременно, от транспортного протокола требуется способность сообщать набор имен групп, связанных с пользователем сервера. Администратору необходимо обеспечить возможность отключить использование этих имен групп в ACM.

2.6. Обслуживание

Требуется обеспечить возможность отключения части или всех процедур выполнения модели контроля доступа без удаления каких-либо правил.

2.7. Возможности настройки

Требуются подходящие механизмы настройки и управления, позволяющие упростить администратору все аспекты управления поведением ACM. Для этого нужна стандартная модель данных, подходящая для использования с протокольной операцией <edit-config>. Требуется поддержка правил управления доступом для ограничения доступа к конкретным субдеревьям внутри конфигурационного хранилища.

2.8. Идентификация требующего защиты содержимого

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

Чувствительные в плане безопасности объекты необходимо указывать в разделе RFC «Вопросы безопасности». Это хорошо, но не достаточно в силу приведенных ниже причин.

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

  • Если риски безопасности идентифицированы, администратор должен дополнительно изучить текст RFC и узнать способы снижения рисков.

  • ACM на каждом сервере требуется настроить для снижения рисков безопасности, например, требуя привилегированного доступа к операциям чтения и записи для конкретных данных, указанных в разделе «Вопросы безопасности».

  • Если ACM не настроена заранее, возникает интервал уязвимости между загрузкой новой модели данных а настройкой, включением и отладкой новых правил контроля доступа для этой модели.

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

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

3. Модель управления доступом для NETCONF (NACM)

3.1. Обзор

В этом разделе представлен общий обзор структуры модели управления доступом. Описана модель обработки протокольных сообщений NETCONF и концептуальные требования к контролю доступа в рамках модели.

3.1.1. Свойства

Возможности модели NACM перечислены ниже.

  • Обеспечивается независимый контроль доступа к RPC, действиям,данным и уведомлениям.

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

  • Используется просто и понятный набор разрешений для хранилища данных.

  • Поддержка меток безопасности YANG (например, оператор nacm:default-deny-write) позволяет автоматически исключать доступ к чувствительным данным по умолчанию.

  • Обеспечиваются раздельные режимы, используемые по умолчанию для чтения, записи и выполнения.

  • Правила контроля доступа применяются к настраиваемым группам пользователей.

  • Процедуры выполнения контроля доступа могут быть отключены в процессе работы без удаления каких-либо правил (для отлаживания при возникновении проблем).

  • Клиент может обеспечивать подсчет отвергнутых запросов на выполнение протокольных операций и запись в хранилище данных.

  • Используются простые неограниченные идентификаторы экземпляров YANG для настройки правил доступа к конкретным узлам данных.

3.1.2. Внешние зависимости

Для целей сетевого управления в этом документе используются протоколы NETCONF [RFC6241] и RESTCONF [RFC8040].

Язык моделирования данных YANG [RFC7950] служит для определения моделей данных, используемых с NETCONF или RESTCONF. YANG также используется для моделей данных в этом документе.

3.1.3. Модель обработки сообщения

На рисунке 2 показана концептуальная модель потока сообщений, включая точки, где применяется контроль доступа в процессе обработки сообщений NETCONF.

Операции RESTCONF отображаются на модель контроля доступа по методу HTTP и классу ресурсов, используемому в операции. Например, метод POST для ресурса данных считается доступом для записи в узел, а метод POST для операции считается доступом operation.

Прямоугольник pre-read data node acc. ctl на рисунке указывает групповой доступ для чтения, поскольку он относится к предкам узла данных для действия или уведомления. Например, если действие определено как /interfaces/interface/reset-interface, группа должна иметь полномочия (1) читать /interfaces и /interfaces/interface, а также (2) выполнять /interfaces/interface/reset-interface.

           +-------------------------+
           |        сессия           |
           |      (username)         |
           +-------------------------+
              |                 ^
              V                 |
    +--------------+     +---------------+
    | диспетчер    |     |  генератор    |
    | сообщений    |     |  сообщений    |
    +--------------+     +---------------+
      |      |               ^         ^
      |      V               |         |
      |  +=============+     |         |
      |  | pre-read    |     |         |
      |  | data node   |     |         |
      |  | acc. ctl    |     |         |
      |  +=============+     |         |
      |    |                 |         |
      V    V                 |         |
+===========+     +-------------+   +----------------+
| operation |---> |  генератор  |   |   генератор    |
| acc. ctl  |     |  откликов   |   | <notification> |
+===========+     +-------------+   +----------------+
      |              ^    ^                ^
      V       +------+    |                |
+-----------+ |   +=============+  +================+
| обработчик| |   |    read     |  | <notification> |
| операции  |-+   | data node   |  |  access ctl    |
|           |     | acc. ctl    |  |                |
+-----------+     +=============+  +================+
      |   |                  ^       ^     ^
      V   +----------------+ |       |     |
+===========+              | |       | +============+
|  write    |              | |       | | pre-read   |
| data node |              | |       | | data node  |
| acc. ctl  | -----------+ | |       | | acc. ctl   |
+===========+            | | |       | +============+
      |                  | | |       |   ^
      V                  V V |       |   |
+---------------+      +-------------------+
|   хранилище   | ---> |      server       |
|  конфигурации |      |  instrumentation  |
|               | <--- |                   |
+---------------+      +-------------------+

Рисунок 2.

Приведенная ниже последовательность концептуальных шагов обработки верхнего уровня выполняется для каждого принятого сообщения <rpc> при включенном контроле доступа.

  • Для каждой активной сессии контроль доступа выполняется индивидуально для всех сообщений <rpc> (кроме <close-session>), полученных сервером, если сессия не идентифицирована как восстановительная.

  • Если вызвана операция <action>, определенная в [RFC7950], доступ к чтению требуется для всех экземпляров в иерархии узлов данных, идентифицирующих указанное действие в хранилище данных, а также требуется доступ к исполнению для узла action. Если пользователь не имеет права читать все указанные узлы данных и выполнять действие, запрос отвергается с возвратом ошибки access-denied.

  • В остальных случаях, если пользователь не имеет права выполнять указанную операцию протокола, запрос отвергается с возвратом ошибки access-denied.

  • При осуществлении протокольной операцией доступа к хранилищу данных, сервер проверяет наличие у пользователя полномочий для доступа к узлам этого хранилища. Если пользователь не имеет полномочий для выполнения запрошенной операции доступа, запрос отвергается с возвратом ошибки access-denied.

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

  • Серверное оборудование генерирует уведомление для определенной подписки.

  • Если в субдереве данных задан оператор notification, как указано в [RFC7950], доступ к чтению требуется для всех экземпляров в иерархии узлов данных, идентифицирующих указанное уведомление в хранилище данных, а также к чтению узла notification. Если пользователь не имеет полномочий для чтения всех заданных узлов данных и узла notification, уведомление для этой подписки отбрасывается.

  • Если notification является оператором верхнего уровня, элемент, выполняющий контроль доступа, проверяет тип связанного с уведомлением события и при отсутствии у пользователя полномочий на чтение, уведомление для этой подписки отбрасывается.

3.2. Доступ к хранилищу данных

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

Все обычные хранилища данных и рабочее хранилище контролируются NACM. Локальные и удаленные файлы или хранилища, доступ к которым осуществляется через параметр <url>, не контролируются NACM.

3.2.1. Отображение новых хранилищ данных в NACM

Возможно, что с течением времени будут определены новые хранилища данных для использования с NETCONF. NACM может применяться к другим хранилищам, в которых права доступа определены подобно NACM. Для применения NACM к новому хранилищу данных, для такого хранилища должно быть определено отображение на права доступа NACM CRUDX5. Возможно, что применима будет лишь часть прав доступа NACM. Например, для хранилищ с доступом только на чтение могут потребоваться лишь контроль поиска информации. Операции и права доступа, не поддерживающие модель NACM CRUDX, выходят за рамки этого документа. Хранилищу данных не требуется использовать NACM, например, спецификация хранилища может определять другой метод или не применять контроль доступа совсем.

3.2.2. Права доступа

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

Модель CRUDX может поддерживать все протокольные операции:

  • создание — позволяет клиенту добавлять новые экземпляры узлов данных в хранилище;

  • чтение — позволяет клиенту читать экземпляры данных из хранилища или получать уведомления о событиях;

  • обновление — позволяет клиенту обновлять имеющиеся экземпляры узлов данных в хранилище;

  • удаление — позволяет клиенту удалять экземпляры узлов данных из хранилища;

  • eXec — позволяет клиенту выполнять операции.

3.2.3. Методы RESTCONF

Протокол RESTCONF использует методы HTTP для выполнения операций с хранилищами данных, подобно протоколу NETCONF. Процедуры NACM разрабатывались для протокола NETCONF, поэтому методы RESTCONF были отображены на операции NETCONF для целей обработки контроля доступа. Процедуры исполнения правил, описанные в этом документе, применимы к обоим протоколам, если явно не указано иное.

При обработке запросов RESTCONF к ресурсам данных нужно рассматривать URI запросов, как описано ниже.

  • Для запросов HEAD и GET любые узлы данных, являющиеся предками узлов целевого ресурса, для целей контроля доступа считаются частью поискового запроса.

  • Для запросов PUT, PATCH и DELETE любые узлы данных, являющиеся предками узлов целевого ресурса, для целей контроля доступа на считаются частью запроса на редактирование. Операцией доступа для таких запросов считается none (нет операции). Редактирование начинается с целевого ресурса.

  • Для запросов POST к ресурсам данных любые узлы данных, указанные в URI запроса, включая целевой ресурс, для целей контроля доступа не считаются частью запроса на редактирование. Операцией доступа для таких запросов считается none. Редактирование начинается на дочернем узле целевого ресурса, заданного в теле сообщения.

Контроль доступа применяется для всех запросов RESTCONF. В приведенной ниже таблице приведены сопоставления запросов с операциями протокола NETCONF. Значение none показывает, что операция NACM не применяется к данному методу RESTCONF.

Таблица 1. Сопоставление методов RESTCONF с NETCONF.

 

Метод

Класс ресурсов

Операция NETCONF

Операция доступа

OPTIONS

все

none

none

HEAD

все

<get>, <get-config>

read

GET

все

<get>, <get-config>

read

POST

хранилище, данные

<edit-config>

create

POST

операция

заданная операция

execute

PUT

данные

<edit-config>

create, update

PUT

хранилище

<copy-config>

update

PATCH

данные, хранилище

<edit-config>

update

DELETE

данные

<edit-config>

delete

 

3.2.4. Операции <get> и <get-config>

Права доступа NACM не связаны напрямую с протокольными операциями <get> и <get-config>, а применяются ко всем операциям <rpc>, которые приводить к операции read для целевого хранилища данных. В этом параграфе описано, как эти права доступа применяются к конкретным операциям доступа, поддерживаемым протокольными операциями <get> и <get-config>.

Узлы данных, к которым клиент не имеет доступа на чтение, просто опускаются вместе с их потомками из сообщения <rpc-reply>. Это делается для того, чтобы обеспечить возможность корректной работы фильтров NETCONF для <get> и <get-config> вместо возврата ошибки access-denied в результате срабатывания фильтров при отсутствии полномочий на чтение некоторых узлов данных. Для целей фильтрации NETCONF критерии выбора применяются к подмножеству узлов, которые пользователь имеет право читать, а не ко всему хранилищу данных.

3.2.5. Операция <edit-config>

Права доступа NACM не связаны напрямую с атрибутом «операции» <edit-config>, хотя они похожи. Права доступа NACM применяются ко всем протокольным операциям, которые в результате будут приводить к определенной операции доступа к целевому хранилищу данных. В это параграфе описано как эти права доступа применяются к конкретным операциям доступа, поддерживаемым протокольной операцией <edit-config>.

Если реальной операцией доступа для отдельного узла данных является none (т. е. default-operation=none), контроль доступа для этого узла не применяется. Это требуется для того, чтобы разрешить доступ к субдереву в более крупной структуре данных. Например, пользователь может иметь полномочия на создание новых записей в списке /interfaces/interface, но не иметь полномочий для создания или удаления его родительского контейнера (/interfaces). Если контейнер /interfaces уже имеется в целевом хранилище, при редактировании списка /interfaces/interface эффективной операцией для узла /interfaces будет none.

Если протокольная операция будет приводить к созданию узла в хранилище данных, а пользователь не имеет полномочий на операцию create для этого узла, операция будет отвергнута с ошибкой access-denied.

Если протокольная операция будет приводить к удалению узла в хранилище данных, а пользователь не имеет полномочий на операцию delete для этого узла, операция будет отвергнута с ошибкой access-denied.

Если протокольная операция будет приводить к изменению узла в хранилище данных, а пользователь не имеет полномочий на операцию update для этого узла, операция будет отвергнута с ошибкой access-denied.

Операция <edit-config> для слияния или замены может включать узлы данных, которые являются неизменяемой частью имеющегося хранилища данных. Например, узел container или list может служить для именования, но не изменения соответствующего узла в хранилище. Такие неизменяемые узлы данных игнорируются сервером и не требуют от клиента каких-либо прав доступа.

Операция <edit-config> для слияния может включать узлы данных, но не включать отдельные дочерние узлы, которые присутствуют в хранилище. Эти отсутствующие узлы данных в области действия операции слияния <edit-config> игнорируются сервером и не требуют от клиента каких-либо прав доступа.

Содержимое конкретных узлов с ограничениями доступа недопустимо включать в какие-либо элементы откликов <rpc-error>.

Операция <edit-config> может приводить к неявному созданию или удалению узлов в результате неявных побочных эффектов запрошенной операции. Например выражение оператора YANG when может давать разные результаты, в зависимости от которых узлы данных могут создаваться или удаляться или при создании узла данных в одной из ветвей оператора YANG choice узлы в других вариантах этого оператора могут неявно удаляться. Для узлов данных, которые неявно изменяются в результате побочных эффектов другой разрешенной операции, не требуется прав доступа NACM.

3.2.6. Операция <copy-config>

Контроль доступа для операции <copy-config> требует специального рассмотрения, поскольку эта операция позволяет администратору полностью заменить содержимое целевого хранилища.

Если источником протокольной операции <copy-config> является хранилище рабочей конфигурации, а целью — хранилище стартовой конфигурации, от клиента требуется лишь доступ к выполнению операции <copy-config>.

В остальных случаях используются приведенные ниже правила.

  • Если источником операции <copy-config> является хранилище, узлы данных, к которым у клиента нет доступа на чтение, просто опускаются.

  • Если целью операции <copy-config> является хранилище данных, клиенту нужен доступ к обновляемым узлам. В частности должны выполняться приведенные ниже условия.

    • Если протокольная операция ведет к созданию узла в хранилище, а пользователь не имеет для этого узла права на создание (create), протокольная операция отвергается с ошибкой access-denied.

    • Если протокольная операция ведет к удалению узла в хранилище, а пользователь не имеет для этого узла права на удаление (delete), протокольная операция отвергается с ошибкой access-denied.

    • Если протокольная операция ведет к обновлению узла в хранилище, а пользователь не имеет для этого узла права на обновление (update), протокольная операция отвергается с ошибкой access-denied.

3.2.7. Операция <delete-config>

Доступ к протокольной операции <delete-config> по умолчанию отвергается. Лист exec-default не применяется к этой операции протокола. Для разрешения вызова этой операции правила контроля доступа должны быть заданы явно, если сессия не является восстановительной.

3.2.8. Операция <commit>

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

Например, если сессия может читать все хранилище, но изменять лишь один лист, эта сессия должна иметь право редактирования и представления (commit) лишь для этого листа.

3.2.9. Операция <discard-changes>

От клиента требуется лишь право выполнять протокольную операцию <discard-changes>. Прав доступа к хранилищу не требуется.

3.2.10. Операция <kill-session>

Операция <kill-session> не меняет хранилища напрямую, однако она позволяет из одной сессии прервать другую, которая могла редактировать хранилище данных.

Доступ к протокольной операции <kill-session> по умолчанию отвергается. Лист exec-default не применяется к этой операции протокола. Для разрешения вызова этой операции правила контроля доступа должны быть заданы явно, если сессия не является восстановительной.

3.3. Компоненты модели

В этом разделе определены концептуальные компоненты, относящиеся к модели контроля доступа.

3.3.1. Пользователи

Пользователь (user) является концептуальным элементом, с которым связаны полномочия доступа, предоставленные для отдельной сессии. Пользователь указывается строкой (именем), которая уникальна в масштабе сервера.

Как описано в [RFC6241], строка имени пользователя выводится из транспортного уровня в процессе организации сессии. Если транспортный уровень не может проверить подлинность пользователя, сессия прерывается.

3.3.2. Группы

Доступ к конкретной операции протокола NETCONF предоставляется для сессии. Сессия связана с группой (т. е. не с пользователем).

Группы идентифицируются по именам. Имена уникальны в масштабе сервера.

Контроль доступа применяется на уровне группы. Группа может быть пустой или включать некоторое число членов.

Члены группы идентифицируются строками имен пользователей.

Один и тот же пользователь может быть членом множества групп.

3.3.3. Сеанс восстановления при аварии

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

3.3.4. Глобальные элементы исполнения

Имеется пять глобальных элементов управления, которые помогают при выполнении контроля доступа.

3.3.4.1. Переключатель enable-nacm

Глобальный переключатель enable-nacm служит для включения и отключения процедур контроля доступа. Когда этот переключатель имеет значение true, все запросы проверяются на соответствие правилам контроля доступа и выполняются только разрешенные запреты на доступ. При значении глобального переключателя false все запросы на доступ разрешены.

3.3.4.2. Переключатель read-default

Переключатель read-default определяет принятый по умолчанию режим доступа к получению данных в откликах и уведомлениях. Когда глобальный переключатель enable-nacm имеет значение true, данный переключатель используется при отсутствии совпадений с правилами контроля доступа, которые явно разрешают или запрещают доступ к запрошенному хранилищу данных или типу уведомления.

Когда этот глобальный переключатель имеет значение permit и нет совпадения с правилом контроля доступа к хранилищу для чтения или получения уведомлений о событиях, такой доступ разрешен.

Когда этот глобальный переключатель имеет значение deny и нет совпадения с правилом контроля доступа к хранилищу для чтения или получения уведомлений о событиях, доступ отвергается. Это означает, что запрошенные данные не будут переданы клиенту (см п. 11 в параграфе 3.4.5).

3.3.4.3. Переключатель write-default

Переключатель write-default определяет принятый по умолчанию режим доступа к изменению конфигурационных данных. Когда глобальный переключатель enable-nacm имеет значение true, данный переключатель используется при отсутствии совпадений с правилами контроля доступа, которые явно разрешают или запрещают доступ для записи в запрошенное хранилище.

Когда этот глобальный переключатель имеет значение permit и нет совпадения с правилом контроля доступа к хранилищу для записи, такой доступ разрешен.

Когда этот глобальный переключатель имеет значение deny и нет совпадения с правилом контроля доступа к записи в запрошенное хранилище, такой доступ отвергается (см п. 12 в параграфе 3.4.5).

3.3.4.4. Переключатель exec-default

Переключатель exec-default определяет принятый по умолчанию режим доступа к выполнению протокольных операций. Когда глобальный переключатель enable-nacm имеет значение true, данный переключатель используется при отсутствии совпадений с правилами контроля доступа, которые явно разрешают или запрещают доступ к исполнению запрошенной операции протокола NETCONF.

Когда этот глобальный переключатель имеет значение permit и нет совпадения с правилом контроля доступа к запрошенной операции протокола NETCONF, такой доступ разрешен.

Когда этот глобальный переключатель имеет значение deny и нет совпадения с правилом контроля доступа к запрошенной операции протокола NETCONF, такой доступ отвергается (см п. 12 в параграфе 3.4.4 и п. 13 в параграфе 3.4.5).

3.3.4.5. Переключатель enable-external-groups

Когда этот глобальный переключатель имеет значение true, имена групп, сообщенные транспортным уровнем для сессии, используются вместе с заданными локально именами групп для определения правил контроля доступа в сессии.

При значении этого переключателя false имена групп, сообщенные транспортным уровнем, игнорируются NACM.

3.3.5. Правила контроля доступа

В NACM доступны 4 типа правил, перечисленные ниже.

module – правило для модуля

Управляет доступом к определениям в модуле YANG, указанном именем.

protocol operation – правило для протокольной операции

Управляет доступом к конкретной операции протокола, указанной именем и модулем YANG.

data node – правило для узла данных

Управляет доступом к конкретному узлу данных (и его потомкам), указанному путем в концептуальном документе XML для узла данных.

Notification – правило для уведомлений

Управляет доступом к конкретному типу уведомлений, указанному именем и модулем YANG.

3.4. Процедуры исполнения контроля доступа

Необходимо выполнить 6 этапов проверки, 4 из которых относятся к модели обработки сообщений NETCONF (параграф 3.1.3):

  1. начальные операции;

  2. организация сессии;

  3. обработка ошибок access-denied;

  4. проверка пригодности входящих сообщений RPC;

  5. проверка доступа к узлу данных;

  6. полномочия для исходящих <notification>.

Кроме того, нужно учитывать стартовый режим сервера NETCONF, организацию сессии, а также процедуры обработки ошибок access-denied.

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

3.4.1. Начальные операции

При первом запуске сервера NETCONF конфигурация контроля доступа может отсутствовать. Если это не так, серверу недопустимо разрешать какой-либо доступ для записи в любой сессии, кроме восстановительной.

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

3.4.2. Организация сессии

Модель контроля доступа применяется к четко сформированному содержимому XML, передаваемому между клиентом и сервером после организации сессии и успешного обмена сообщениями <hello>.

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

3.4.3. Обработка ошибок access-denied

Тег ошибки access-denied генерируется в тех случаях, когда система контроля доступа отвергает запрос на вызов протокольной операции или выполнение той или иной операции доступа к хранилищу конфигурации.

Серверу недопустимо включать какую-либо информацию, которую клиенту не разрешено читать, в элементы <error-info> откликов <rpc-error>.

3.4.4. Проверка входящих сообщений RPC

На рисунке 3 показана базовая концептуальная структура модели обработки контроля доступа для входящих сообщений NETCONF <rpc> на сервере.

         Сервер NETCONF 
         +------------+
         | Диспетчер  |
         | сообщений  |
         |    XML     |
         +------------+
                |
                |
                V
        +---------------+
        |сообщение <rpc>|
        +---------------+
          |    |     |
          |    |     +--------------------------------+
          |    +---------------+                      |
          V                    V                      V
+------------------+ +--------------------+ +--------------------+
|фирменная операция| |стандартная операция| |стандартная операция|
|    <my-edit>     | |   <edit-config>    | |      <unlock>      |
+------------------+ +--------------------+ +--------------------+
            |                 |
            |                 |
            V                 V
           +----------------------+
           |      Хранилище       |
           |    конфигурации      |
           +----------------------+

Рисунок 3.

Контроль доступа начинается с диспетчера сообщений.

После проверки сервером пригодности элемента <rpc>, определения пространства имен URI и имени элемента, запрашивающего протокольную операцию сервер проверяет права пользователя на вызов протокольной операции.

Сервер должен отдельно разрешать каждую операцию протокола, выполняя перечисленные ниже шаги.

  1. Если лист enable-nacm имеет значение false, протокольная операция разрешена.

  2. Если запрашивающая сессия определена как восстановительная, протокольная операция разрешена.

  3. Если запрошена операция NETCONF <close-session>, протокольная операция разрешена.

  4. Проверяются все записи group для поиска в них записи user-name, значение которой совпадает с именем пользователя для сделавшей запрос сессии. Если лист enable-external-groups имеет значение true, эти группы добавляются в список групп, предоставленный транспортным уровнем.

  5. Если групп не найдено, переход к п. 10.

  6. Обрабатываются все записи rule-list в порядке их размещения в конфигурации. Если в rule-list элемент leaf-list для групп не совпадает ни с одной из групп пользователя, обрабатывается следующий элемент rule-list.

  7. Для каждого найденного элемента rule-list обрабатываются все записи по порядку, пока не будет найдено правило, соответствующее запрошенной операции доступа. Правило считается соответствующим при выполнении всех перечисленных ниже условий.

    • Лист module-name в правиле имеет значение * или совпадает с именем модуля YANG, где определена протокольная операция.

    • (1) правило не имеет rule-type или (2) rule-type имеет значение protocol-operation, а rpc-name имеет значение * или совпадает с именем запрошенной операции протокола.

    • Лист access-operations в правиле имеет установленный бит exec или специальное значение *.

  8. Если соответствующее правило найдено, проверяется лист action. Если он имеет значение permit, протокольная операция разрешена, в противном случае она отвергается.

  9. Этот пункт соответствует ситуации, когда не найдено совпадающего правила ни в одной записи rule-list.

  10. Если запрошенная протокольная операция определена в модуле YANG, анонсированном в возможностях сервера, и оператор rpc содержит оператор nacm:default-deny-all, протокольная операция отвергается.

  11. Если протокольная операция является операцией протокола NETCONF <kill-session> или <delete-config>, эта операция отвергается.

  12. Если лист exec-default имеет значение permit, протокольная операция разрешена, иначе она отвергается.

Если пользователь не уполномочен вызывать операцию протокола, генерируется сообщение <rpc-error> с приведенной ниже информацией.

error-tag

access-denied

error-path

Указывает запрошенную операцию. Приведенный ниже пример представляет операцию <edit-config> в базовом пространстве имен NETCONF.

         <error-path
           xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
             /nc:rpc/nc:edit-config
         </error-path>

Если доступ к хранилищу произошел (напрямую или за счет побочного эффекта протокольной операции), сервер должен перехватить операцию доступа и убедиться, что пользователь уполномочен на выполнение запрошенной операции доступа к указанным данным, как описано в параграфе 3.4.5.

3.4.5. Проверка доступа к узлу данных

Если (1) осуществляется доступ к узлу данных или (2) к узлу привязано действие или уведомление, сервер должен гарантировать, что пользователь уполномочен выполнять запрошенную операцию доступа read, create, update, delete или execute для указанного узла данных.

Если запрошено выполнение действия, сервер должен гарантировать, что пользователь уполномочен выполнять операцию доступа execute.

Если генерируется привязанное к узлу уведомление, сервер должен гарантировать, что пользователь уполномочен выполнять операцию доступа read для запрошенного уведомления.

Этапы проверки полномочий доступа к узлу данных перечислены ниже.

  1. Если лист enable-nacm имеет значение false, доступ разрешен.

  2. Если запрашивающая сессия определена как восстановительная, доступ разрешен.

  3. Проверяются все записи group для поиска в них записи user-name, значение которой совпадает с именем пользователя для сделавшей запрос сессии. Если лист enable-external-groups имеет значение true, эти группы добавляются в список групп, предоставленный транспортным уровнем.

  4. Если групп не найдено, переход к п. 9.

  5. Обрабатываются все записи rule-list в порядке их размещения в конфигурации. Если в rule-list элемент leaf-list для групп не совпадает ни с одной из групп пользователя, обрабатывается следующий элемент rule-list.

  6. Для каждого найденного элемента rule-list обрабатываются все записи по порядку, пока не будет найдено правило, соответствующее запрошенной операции доступа. Правило считается соответствующим при выполнении всех перечисленных ниже условий.

    • Лист module-name в правиле имеет значение * или совпадает с именем модуля YANG, где определена протокольная операция.

    • (1) правило не имеет rule-type или (2) rule-type имеет значение data-node, а path соответствует запрашиваемому узлу данных, действия или уведомления. Путь считается соответствующим, если запрошенный узел является узлом, заданным этим путем, или наследником такого узла.

    • Для операции read лист access-operations в правиле имеет установленный бит read или специальное значение *.

    • Для операции create лист access-operations в правиле имеет установленный бит create или специальное значение *.

    • Для операции delete лист access-operations в правиле имеет установленный бит delete или специальное значение *.

    • Для операции update лист access-operations в правиле имеет установленный бит update или специальное значение *.

    • Для операции execute лист access-operations в правиле имеет установленный бит exec или специальное значение *.

  1. Если соответствующее правило найдено, проверяется лист action. Если он имеет значение permit, протокольная операция разрешена, в противном случае она отвергается. Для операции read отказ (denied) означает, что запрошенные данные не возвращаются в отклике.

  2. Этот пункт соответствует ситуации, когда не найдено совпадающего правила ни в одной записи rule-list.

  3. Если запрошенный узел данных для операции read определен в модуле YANG, анонсированном в возможностях сервера и оператор определения данных содержит оператор nacm:default-deny-all, запрошенный узел данных и все его наследники не включаются в отклик.

  4. Если запрошенный узел данных для операции write определен в модуле YANG, анонсированном в возможностях сервера, и оператор определения данных содержит оператор nacm:default-deny-write или nacm:default-deny-all, запрошенная операция отвергается для узла данных и всех его наследников.

  5. Если для операции read лист read-default имеет значение permit, запрошенный узел включается в отклик, в противном случае запрошенный узел и все его потомки не включаются в отклик.

  6. Если для операции write лист write-default имеет значение permit, запрос разрешается, иначе отвергается.

  7. Если для операции execute лист exec-default имеет значение permit, запрос разрешается, иначе отвергается.

3.4.6. Предоставление полномочий для исходящего уведомления

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

Если уведомление задано в субдереве данных, как указано в [RFC7950], требуется доступ для чтения к уведомлению. Обработка продолжается в соответствии с параграфом 3.4.5.

На рисунке 4 показана концептуальная модель обработки для исходящих сообщений <notification>.

      Сервер NETCONF 
      +------------+
      |  Генератор |
      |  сообщений |
      |     XML    |
      +------------+
            ^
            |
    +----------------+
    |   Генератор    |
    | <notification> |
    +----------------+
            ^
            |
   +=================+
   | <notification>  |
   |контроль доступа |
   |  <eventType>    |
   +=================+
            ^
            |
+------------------------+
| Оборудование сервера   |
+------------------------+
          |     ^
          V     |
 +----------------------+
 |      Хранилище       |
 |     конфигурации     |
 +----------------------+

Рисунок 4.


Для генерации уведомления по указанной подписке [RFC5277] полномочия выдаются в соответствии с приведенным ниже описанием.

  1. Если лист enable-nacm имеет значение false, уведомление разрешено.

  2. Если сессия определена как восстановительная, уведомление разрешено.

  3. Если уведомление относится к типу NETCONF <replayComplete> или <notificationComplete> [RFC5277], оно разрешено.

  4. Проверяются все записи group для поиска в них записи user-name, значение которой совпадает с именем пользователя для сделавшей запрос сессии. Если лист enable-external-groups имеет значение true, эти группы добавляются в список групп, предоставленный транспортным уровнем.

  5. Если групп не найдено, переход к п. 10.

  6. Обрабатываются все записи rule-list в порядке их размещения в конфигурации. Если в rule-list элемент leaf-list для групп не совпадает ни с одной из групп пользователя, обрабатывается следующий элемент rule-list.

  7. Для каждого найденного элемента rule-list обрабатываются все записи по порядку, пока не будет найдено правило, соответствующее запрошенной операции доступа. Правило считается соответствующим при выполнении всех перечисленных ниже условий.

    • Лист module-name в правиле имеет значение * или совпадает с именем модуля YANG, где определено уведомление.

    • (1) правило не имеет rule-type или (2) rule-type имеет значение notification, а notification-name имеет значение * или совпадает с именем уведомления.

    • Лист access-operations в правиле имеет установленный бит read или специальное значение *.

  1. Если соответствующее правило найдено, проверяется лист action. Если он имеет значение permit, протокольная уведомление разрешено, в противном случае оно отбрасывается.

  2. Этот пункт соответствует ситуации, когда не найдено совпадающего правила ни в одной записи rule-list.

  3. Если запрошенное уведомление определено в модуле YANG, анонсированном в возможностях сервера, и оператор notification содержит оператор nacm:default-deny-all, уведомление для соответствующей подписки отбрасывается.

  4. Если для лист read-default имеет значение permit, уведомление разрешено, в противном случае оно отвергается.

3.5. Определения модели данных

3.5.1. Организация данных

На приведенном ниже рисунке показана структура и содержимое модуля NACM YANG.

   module: ietf-netconf-acm
     +--rw nacm
        +--rw enable-nacm?              boolean
        +--rw read-default?             action-type
        +--rw write-default?            action-type
        +--rw exec-default?             action-type
        +--rw enable-external-groups?   boolean
        +--ro denied-operations         yang:zero-based-counter32
        +--ro denied-data-writes        yang:zero-based-counter32
        +--ro denied-notifications      yang:zero-based-counter32
        +--rw groups
        |  +--rw group* [name]
        |     +--rw name         group-name-type
        |     +--rw user-name*   user-name-type
        +--rw rule-list* [name]
           +--rw name     string
           +--rw group*   union
           +--rw rule* [name]
              +--rw name                 string
              +--rw module-name?         union
              +--rw (rule-type)?
              |  +--:(protocol-operation)
              |  |  +--rw rpc-name?            union
              |  +--:(notification)
              |  |  +--rw notification-name?   union
              |  +--:(data-node)
              |     +--rw path                 node-instance-identifier
              +--rw access-operations?   union
              +--rw action               action-type
              +--rw comment?             string

3.5.2. Модуль YANG

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

Модуль YANG ietf-netconf-acm импортирует определения типов из [RFC6991].

   <CODE BEGINS> file "ietf-netconf-acm@2018-02-14.yang"
   module ietf-netconf-acm {

     namespace "urn:ietf:params:xml:ns:yang:ietf-netconf-acm";

     prefix nacm;

     import ietf-yang-types {
       prefix yang;
     }

     organization
       "IETF NETCONF (Network Configuration) Working Group";

     contact
       "WG Web:   <https://datatracker.ietf.org/wg/netconf/> 
        WG List:  <mailto:netconf@ietf.org> 

        Author:   Andy Bierman
                  <mailto:andy@yumaworks.com> 

        Author:   Martin Bjorklund
                  <mailto:mbj@tail-f.com>"; 

     description
       "Модель управления доступом NETCONF.

        Copyright (c) 2012 - 2018 IETF Trust and the persons
        identified as authors of the code.  All rights reserved.

        Распространение и использование в исходной или двоичной форме
        с изменениями или без таковых разрешается в соответствии с 
        упрощенной лицензией BSD, изложенной в параграфе 4.c документа
        IETF Trust's Legal Provisions Relating to IETF Documents
        (https://trustee.ietf.org/license-info). 

        Данная версия модуля YANG является частью RFC 8341, где правовые
        вопросы рассмотрены более полно.";

     revision "2018-02-14" {
       description
         "Добавлена поддержка действий и уведомлений YANG 1.1, привязанных
          к узлам данных. Уточнено использование расширений NACM в других
          моделях данных.";
       reference
         "RFC 8341: Network Configuration Access Control Model";
     }

     revision "2012-02-22" {
       description
         "Initial version.";
       reference
         "RFC 6536: Network Configuration Protocol (NETCONF)
                    Access Control Model";
     }

     /*
      * Extension statements
      */

     extension default-deny-write {
       description
         "Служит для индикации того, что узел модели данных
          представляет деликатный параметр безопасности системы.

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

          Если используется модуль NACM, он должен быть включен (т. е.
          объект /nacm/enable-nacm должен иметь значение true) или это
          расширение будет игнорироваться.

          Расширение default-deny-write МОЖЕТ присутствовать лишь в
          операторе определения данных. В иных случаях оно игнорируется.";
     }

     extension default-deny-all {
       description
         "Используется для указания того, что узел модели данных управляет
          очень деликатным параметром безопасности.

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

          Если используется модуль NACM, он должен быть включен (т. е.
          объект /nacm/enable-nacm должен иметь значение true) или это
          расширение будет игнорироваться.

          Расширение default-deny-all МОЖЕТ присутствовать лишь в
          операторе определения данных, операторе rpc или notification.
          statement. В иных случаях оно игнорируется.";
     }

     /*
      * Производные типы
      */

     typedef user-name-type {
       type string {
         length "1..max";
       }
       description
         "Строка общего назначения для имени пользователя.";
     }

     typedef matchall-string-type {
       type string {
         pattern '\*';
       }
       description
         "Строка, содержащая один символ *, используется для 
          представления всех возможных значений отдельного листа,
          использующего этот тип данных.";
     }

     typedef access-operations-type {
       type bits {
         bit create {
           description
             "Любая операция протокола, создающая новый узел данных.";
         }
         bit read {
           description
             "Любая операция протокола или уведомление, возвращающие
              значение узла данных.";
         }
         bit update {
           description
             "Любая операция протокола, изменяющая узел данных.";
         }

         bit delete {
           description
             "Любая операция протокола, удаляющая узел данных.";
         }
         bit exec {
           description
             "Выполнение заданной операции протокола.";
         }
       }
       description
         "Операция доступа.";
     }

     typedef group-name-type {
       type string {
         length "1..max";
         pattern '[^\*].*';
       }
       description
         "Имя группы администраторов, в которую можно назначить
          пользователей.";
     }

     typedef action-type {
       type enumeration {
         enum permit {
           description
             "Запрошенное действие разрешено.";
         }
         enum deny {
           description
             "Запрошенное действие отвергнуто.";
         }
       }
       description
         "Действие, выполняемое сервером при соответствии 
          конкретному правилу.";
     }

     typedef node-instance-identifier {
       type yang:xpath1.0;
       description
         "Путь, используемый для представления строки идентификатора
          специального узла данных, действия или уведомления.

          Значением идентификатора экземпляра узла является
          выражение YANG instance-identifier без ограничений.

          Применяются те же правила, что и instance-identifier,
          за исключением необязательности предикатов ключей. При
          отсутствии предиката node-instance-identifier представляет
          все возможные экземпляры сервера для этого ключа.

          Это выражение XML Path Language (XPath) оценивается в описанном
          ниже контексте.

             -  Набор деклараций пространств имен включает те, что находятся
                в области действия элемента leaf, где используется тип.

             -  Набор привязок переменных содержит одну переменную USER, 
                которая указывает имя пользователя текущей сессии.

             -  Библиотекой функций служит библиотека ядра, но следует
                отметить, что синтаксические ограничения instance-identifier
                не разрешают функций.

             -  Узлом контекста является корневой узел дерева данных.

          Доступное дерево включает действия и уведомления, привязанные
          к узлам данных.";
     }

     /*
      * Операторы определения данных
      */

     container nacm {
       nacm:default-deny-all;

       description
         "Параметры для модели управления доступом NETCONF.";

       leaf enable-nacm {
         type boolean;
         default "true";
         description
           "Разрешает или запрещает выполнение всех операций 
            контроля доступа NETCONF. Значение true включает
            управление, false отключает.";
       }

       leaf read-default {
         type action-type;
         default "permit";
         description
           "Решает вопрос предоставления доступа на чтение при
            отсутствии подходящего правила для конкретного запроса.";
       }

       leaf write-default {
         type action-type;
         default "deny";
         description
           "Решает вопрос предоставления доступа на создание,
            изменение или удаление при отсутствии подходящего
            правила для конкретного запроса.";
       }

       leaf exec-default {
         type action-type;
         default "permit";
         description
           "Решает вопрос предоставления доступа на исполнение при
            отсутствии подходящего правила для конкретного запроса.";
       }

       leaf enable-external-groups {
         type boolean;
         default "true";
         description
           "Задает, будет ли сервер использовать группы, переданные 
            транспортным уровнем NETCONF при назначении пользователя для
            набора групп NACM. Если этот лист имеет значение false, все
            имена групп, сообщенные транспортным уровнем, сервер игнорирует.";
       }

       leaf denied-operations {
         type yang:zero-based-counter32;
         config false;
         mandatory true;
         description
           "Число случаев отказа от выполнения протокольных операций
            с момента последней перезагрузки сервера.";
       }

       leaf denied-data-writes {
         type yang:zero-based-counter32;
         config false;
         mandatory true;
         description
           "Число случаев отказа от выполнения протокольной операции
            изменения хранилища данных  с момента последней 
            перезагрузки сервера.";
       }

       leaf denied-notifications {
         type yang:zero-based-counter32;
         config false;
         mandatory true;
         description
           "Число случаев отказа от предоставления подписки на 
            уведомления с момента последней перезагрузки сервера.";
       }

       container groups {
         description
           "Группы контроля доступа NETCONF.";

         list group {
           key name;

           description
             "Запись для одной группы NACM. Этот список будет 
              включать лишь заданные в конфигурации, а не полученные 
              от транспортных протоколов записи.";

           leaf name {
             type group-name-type;
             description
               "Имя группы, связанной с этой записью.";
           }

           leaf-list user-name {
             type user-name-type;
             description
               "Каждая запись указывает имя пользователя - члена
                группы, связанной с записью.";
           }
         }
       }

       list rule-list {
         key name;
         ordered-by user;
         description
           "Упорядоченный набор правил контроля доступа.";

         leaf name {
           type string {
             length "1..max";
           }
           description
             "Произвольное имя, назначенное для rule-list.";
         }
         leaf-list group {
           type union {
             type matchall-string-type;
             type group-name-type;
           }
           description
             "Список административных групп, которым будут 
              назначены права доступа, заданные списком rule.

              * указывает, что запись применяется ко всем группам.";
         }

         list rule {
           key name;
           ordered-by user;
           description
             "Одно правило управления доступом.

              Правила обрабатываются в заданном пользователем порядке до 
              первого совпадения. Совпадением считается соответствие 
              module-name, rule-type и access-operations запросу. Если
              правило соответствует, лист action определяет 
              предоставление доступа.";

           leaf name {
             type string {
               length "1..max";
             }
             description
               "Произвольное имя, назначенное для правила.";
           }

           leaf module-name {
             type union {
               type matchall-string-type;
               type string;
             }
             default "*";
             description
               "Имя модуля, связанного с данным правилом.

                Этот лист дает совпадение, если он имеет значение * или 
                объект, требующий доступа, определен в модуле с заданным 
                именем.";
           }
           choice rule-type {
             description
               "Этот выбор будет соответствовать, если все листья в правиле
                соответствуют запросу. При отсутствии листьев выбор 
                соответствует всем запросам.";
             case protocol-operation {
               leaf rpc-name {
                 type union {
                   type matchall-string-type;
                   type string;
                 }
                 description
                   "Этот лист (leaf) считается соответствующим, если он имеет 
                    значение * или его значение совпадает с именем запрошенной
                    протокольной операции.";
               }
             }
             case notification {
               leaf notification-name {
                 type union {
                   type matchall-string-type;
                   type string;
                 }
                 description
                   "Этот лист (leaf) считается соответствующим, если он имеет 
                    значение * или его значение совпадает с именем запрошенного
                    уведомления.";
               }
             }

             case data-node {
               leaf path {
                 type node-instance-identifier;
                 mandatory true;
                 description
                   "Идентификатор экземпляра, связанный с узлом данных,
                    действием или уведомлением, контролируемым данным
                    правилом.

                    Идентификаторы экземпляров данных конфигурации или
                    состояния начинаются в узла данных верхнего уровня.
                    Для этого типа значения пути нужен полный идентификатор
                    экземпляра.

                    Специальное значение / указывает все содержимое хранилища.";
               }
             }
           }

           leaf access-operations {
             type union {
               type matchall-string-type;
               type access-operations-type;
             }
             default "*";
             description
               "Операции доступа, связанные с этим правилом.

                Лист будет соответствовать, если он имеет значение * или
                бит, соответствующий запрашиваемой операции, установлен.";
           }

           leaf action {
             type action-type;
             mandatory true;
             description
               "Действие по управлению доступом, связанное с правилом.
                Если определено, что правило соответствует конкретному
                запросу, этот объект указывает, принимается или 
                отвергается запрос.";
           }

           leaf comment {
             type string;
             description
               "Текстовое описание правила доступа.";
           }
         }
       }
     }
   }

   <CODE ENDS>

4. Взаимодействие с IANA

Этот документ повторно использует URI для ietf-netconf-acm в реестре IETF XML.

Документ обновляет регистрацию модуля в реестре YANG Module Names ссылкой на данный RFC вместо RFC 6536 для ietf-netconf-acm. В соответствии с форматом в [RFC6020] регистрируются приведенные ниже параметры.

        Name: ietf-netconf-acm
        Namespace: urn:ietf:params:xml:ns:yang:ietf-netconf-acm
        Prefix: nacm
        Reference: RFC 8341

5. Вопросы безопасности

Описанный в этом документе модуль YANG определяет схему для данных, которая разработана для обеспечения доступа с помощью протоколов сетевого управления типа NETCONF [RFC6241] или RESTCONF [RFC8040]. Нижним уровнем NETCONF является защищенный транспорт и обязательным для реализации является защищенный транспорт SSH6 [RFC6242]. Нижним уровнем RESTCONF является протокол HTTPS и обязательный для реализации транспорт TLS [RFC5246].

Модель контроля доступа NETCONF [RFC8341] обеспечивает способы ограничения доступа для отдельных пользователей NETCONF или RESTCONF к предопределенному подмножеству всех доступных протокольных операций и содержимого NETCONF или RESTCONF.

Имеется риск, связанный с недостаточным контролем доступа для опций RESTCONF и методов PATCH. Риск заключается в том, что отклик на OPTIONS и PATCH может варьироваться в зависимости от наличия или отсутствия ресурса, соответствующего пути URL. Это может быть использовано для тривиальной проверки наличия или отсутствия значений в дереве. Поэтому серверу недопустимо менять свои отклики в зависимости от существования ресурса, что может показать наличие или отсутствие экземпляров ресурса. В частности, не следует выдавать какую-либо информацию об экземпляре без уверенности в том, что клиент имеет полномочия, требуемые для такого доступа. Предполагается, что сервер всегда возвращает отклик об ошибке access-denied.

Для многих узлов данных, определенных в этом модуле YANG, возможна запись/создание/удаление (т. е. config имеет значение true, установленное по умолчанию). Такие узлы могут считаться чувствительными или уязвимыми в некоторых сетевых средах. Операции записи (например, edit-config) в такие узлы без надлежащей защиты могут оказывать негативное влияние на работу сети. Ниже перечислены субдеревья и узлы данных с указанием их чувствительности/уязвимости:

  • /nacm: все субдерево /nacm связано с безопасностью (см. подробности в последующих параграфах).

Далее очерчены вопросы, которые администратору нужно рассмотреть при настройке сервера NETCONF с NACM.

5.1. Настройка и мониторинг NACM

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

По умолчанию выполнение NACM включено. По умолчанию доступ read разрешен для всего содержимого хранилища данных (пока в определении данных не задано nacm:default-deny-all), доступ exec разрешен для безопасных операций протокола. Администратор должен обеспечить включение NACM, а также решить, правильно ли настроены принятые по умолчанию параметры. Нужно убедиться в корректности настройки перечисленных ниже узлов данных и параметров:

  • /nacm/enable-nacm (по умолчанию true)

  • /nacm/read-default (по умолчанию permit)

  • /nacm/write-default (по умолчанию deny)

  • /nacm/exec-default (по умолчанию permit)

Администратору нужно ограничить доступ для записи ко всем настраиваемым объектам внутри этой модели данных.

Если разрешена запись для настройки конфигурации правил контроля доступа, нужны меры предотвращения нарушений при выполнении правил контроля доступа. Например, если правила контроля доступа NACM нужно редактировать напрямую в хранилище рабочей конфигурации (т. е. поддерживается и применяется возможность writable-running), нужно принять меры предотвращения непреднамеренного доступа во время редактирования.

Администратор должен убедиться, что трансляция зависящего от транспорта или реализации отождествления пользователя в имя пользователя NACM однозначна и корректна. Это требование подробно описано в параграфе 2.2 [RFC6241].

Администратор должен знать, что структуры данных YANG, представляющие правила контроля доступа (/nacm/rule-list и /nacm/rule-list/rule), упорядочены клиентом. Сервер будет проверять правила контроля доступа в соответствии с их относительным концептуальным порядком в хранилище рабочей конфигурации.

Отметим, что структура данных /nacm/groups содержит имена административных групп, используемых сервером. Эти имена групп могут настраиваться локально и/или через внешний протокол типа RADIUS [RFC2865] [RFC5607].

Для определения имен групп администратор должен понимать свойства безопасности всех внешних протоколов, используемых транспортным уровнем. Например, если протокол не обеспечивает защиты от MITM-атак7, атакующий может подставить имена групп, которые будут затем включены в конфигурацию NACM так, что пользователь получит избыточные полномочия. В таких случаях администратор может отключить такие имена групп, установив для /nacm/enable-external-groups значение false.

Некоторые из доступных для чтения узлов данных в этом модуле YANG могут оказаться чувствительными или уязвимыми в отдельных сетевых средах. Для таких узлов важно контролировать доступ на чтение (например, с помощью get, get-config или notification). Ниже перечислены чувствительные/уязвимые субдеревья и узлы данных:

  • /nacm/enable-nacm

  • /nacm/read-default

  • /nacm/write-default

  • /nacm/exec-default

  • /nacm/enable-external-groups

  • /nacm/groups

  • /nacm/rule-list

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

5.2. Общие вопросы настройки конфигурации

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

Для сессии с некоторыми правами записи (например, вызов <edit-config>), но без какого-либо доступа к конкретному субдереву с конфиденциальными данными можно определить наличие или отсутствие таких данных. Это можно сделать путем повторяющихся вызовов некой операции редактирования (создание, обновление или удаление) с возможным получением отклика access-denied. Такая «ловля на живца» может определить наличие или отсутствие конкретных чувствительных данных даже без наличия поля error-path в отклике <rpc-error>.

Набор возможностей сервера NETCONF может меняться с течением времени. В таких случаях возникает риск добавления на устройстве новых протокольных операций, уведомлений и/или содержимого хранилища. Администратор должен убедиться в том, что правила контроля доступа в этом случае подходят для новых условий. Механизмы обнаружения смены возможностей NETCONF на конкретном устройстве выходят за рамки документа.

Возможно, что само определение модели данных (например, оператор YANG when) будет помогать при несанкционированном доступе определить присутствие и даже значение узлов деликатных данных путем проверки наличия и значений разных узлов данных.

Возможно, что само определение модели данных (например, оператор YANG when или choice) позволит сессии неявно создавать или удалять узлы, для которых сессия не имеет прав записи, за счет побочных эффектов при обработке разрешенной операции <edit-config>.

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

Модель данных может содержать внешние ключи (например, YANG leafref), которые раскрывают значения из другой структуры данных. Администратор должен осознавать деликатность моделей данных с узлами leafref. Это влечет за собой поиск всех объектов leafref, которые «указывают» на деликатные данные (т. е. значений операторов path), явно или неявно включая узлы конфиденциальных данных.

Определение процедур исполнения контроля доступа для базового оборудования, которое может использоваться для поддержки работы сервера NETCONF, выходит за рамки документа. Администратор может идентифицировать выполняемые сервером протокольные операции и решить вопросы применения для них контроля доступа.

Этот документ включает необязательное использование механизма сессий восстановления, который может применяться для обхода правил контроля доступа в критических ситуациях типа конфигурационных ошибок NACM, которые полностью блокируют доступ к серверу. Настройка и идентификация такого механизма сеансов восстановления зависит от реализации и выходит за рамки этого документа. Администратор должен знать все механизмы сеансов восстановления, доступные на сервере и убедиться в их надлежащем использовании.

Сессия может нарушать управление конфигурацией даже без права записи в конфигурацию просто путем блокировки хранилища. Это может делаться для обеспечения стабильности всей или части конфигурации во время операций извлечения данных или возникать в результате DoS-атаки8. Сервер не может различить эти два случая. Администратор может ограничить доступ к исполнению (exec) для перечисленных ниже протокольных операций:

  • <lock>

  • <unlock>

  • <partial-lock>

  • <partial-unlock>

5.3. Устройство модели данных

Разработчикам нужно четко указать все деликатные данные, уведомления и протокольные операции, определенные в модуле YANG. Для таких определений должен присутствовать оператор nacm:default-deny-write или nacm:default-deny-all в дополнение к четкому описанию рисков безопасности.

Протокольные операции должны быть подобающим образом документированы разработчиком модели данных, чтобы администраторы понимали на какие узлы данных (если они есть) влияют операции протокола и какая информация (если она есть) возвращается в сообщении <rpc-reply>.

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

6. Литература

6.1. Нормативные документы

[RFC2119] Bradner, S., «Key words for use in RFCs to Indicate Requirement Levels», BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, <https://www.rfc-editor.org/info/rfc2119>.

[RFC5246] Dierks, T. and E. Rescorla, «The Transport Layer Security (TLS) Protocol Version 1.2», RFC 5246, DOI 10.17487/RFC5246, August 2008, <https://www.rfc-editor.org/info/rfc5246>.

[RFC5277] Chisholm, S. and H. Trevino, «NETCONF Event Notifications», RFC 5277, DOI 10.17487/RFC5277, July 2008, <https://www.rfc-editor.org/info/rfc5277>.

[RFC6020] Bjorklund, M., Ed., «YANG — A Data Modeling Language for the Network Configuration Protocol (NETCONF)», RFC 6020, DOI 10.17487/RFC6020, October 2010, <https://www.rfc-editor.org/info/rfc6020>.

[RFC6241] Enns, R., Ed., Bjorklund, M., Ed., Schoenwaelder, J., Ed., and A. Bierman, Ed., «Network Configuration Protocol (NETCONF)», RFC 6241, DOI 10.17487/RFC6241, June 2011, <https://www.rfc-editor.org/info/rfc6241>./WP/rfc6242/

[RFC6242] Wasserman, M., «Using the NETCONF Protocol over Secure Shell (SSH)», RFC 6242, DOI 10.17487/RFC6242, June 2011, <https://www.rfc-editor.org/info/rfc6242>.

[RFC6991] Schoenwaelder, J., Ed., «Common YANG Data Types», RFC 6991, DOI 10.17487/RFC6991, July 2013, <https://www.rfc-editor.org/info/rfc6991>.

[RFC7230] Fielding, R., Ed., and J. Reschke, Ed., «Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing», RFC 7230, DOI 10.17487/RFC7230, June 2014, <https://www.rfc-editor.org/info/rfc7230>.

[RFC7950] Bjorklund, M., Ed., «The YANG 1.1 Data Modeling Language», RFC 7950, DOI 10.17487/RFC7950, August 2016, <https://www.rfc-editor.org/info/rfc7950>.

[RFC8040] Bierman, A., Bjorklund, M., and K. Watsen, «RESTCONF Protocol», RFC 8040, DOI 10.17487/RFC8040, January 2017, <https://www.rfc-editor.org/info/rfc8040>.

[RFC8174] Leiba, B., «Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words», BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017, <https://www.rfc-editor.org/info/rfc8174>.

[RFC8342] Bjorklund, M., Schoenwaelder, J., Shafer, P., Watsen, K., and R. Wilton, «Network Management Datastore Architecture (NMDA)», RFC 8342, DOI 10.17487/RFC8342, March 2018, <https://www.rfc-editor.org/info/rfc8342>.

[W3C.REC-xml-20081126] Bray, T., Paoli, J., Sperberg-McQueen, M., Maler, E., and F. Yergeau, «Extensible Markup Language (XML) 1.0 (Fifth Edition)», World Wide Web Consortium Recommendation REC-xml-20081126, November 2008, <https://www.w3.org/TR/2008/REC-xml-20081126>.

6.2. Дополнительная литература

[RFC2865] Rigney, C., Willens, S., Rubens, A., and W. Simpson, «Remote Authentication Dial In User Service (RADIUS)», RFC 2865, DOI 10.17487/RFC2865, June 2000, <https://www.rfc-editor.org/info/rfc2865>.

[RFC5607] Nelson, D. and G. Weber, «Remote Authentication Dial-In User Service (RADIUS) Authorization for Network Access Server (NAS) Management», RFC 5607, DOI 10.17487/RFC5607, July 2009, <https://www.rfc-editor.org/info/rfc5607>.

[YANG-SEC] IETF, «YANG Security Guidelines», <https://trac.ietf.org/trac/ops/wiki/yang-security-guidelines>.

Приложение A. Примеры использования

Приведенные ниже фрагменты XML [W3C.REC-xml-20081126] служат лишь примерами настройки NACM для решения некоторых задач контроля доступа.

A.1. Пример <groups>

Требуется хотя бы одна запись <group>, чтобы правила контроля доступа могли использоваться.

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

   <nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm">
     <groups>
       <group>
         <name>admin</name>
         <user-name>admin</user-name>
         <user-name>andy</user-name>
       </group>

       <group>
         <name>limited</name>
         <user-name>wilma</user-name>
         <user-name>bam-bam</user-name>
       </group>

       <group>
         <name>guest</name>
         <user-name>guest</user-name>
         <user-name>guest@example.com</user-name>
       </group>
     </groups>
   </nacm>

Этот пример включает три группы:

   admin: два пользователя с именами admin и andy
   limited: два пользователя с именами wilma и bam-bam
   guest: два пользователя с именами guest и guest@example.com.

A.2. Пример правила для модуля

Правила модуля служат для контроля доступа ко всему содержимому, определенному в конкретном модуле. Правило модуля имеет установленный лист module-name, но не имеет установленных узлов из выбора rule-type.

   <nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm">
     <rule-list>
       <name>guest-acl</name>
       <group>guest</group>
       <rule>
         <name>deny-ncm</name>
         <module-name>ietf-netconf-monitoring</module-name>
         <access-operations>*</access-operations>
         <action>deny</action>
         <comment>
             Не позволяет гостям получить доступ к данным 
             мониторинга NETCONF.
         </comment>
       </rule>
     </rule-list>

     <rule-list>
       <name>limited-acl</name>
       <group>limited</group>
       <rule>
         <name>permit-ncm</name>
         <module-name>ietf-netconf-monitoring</module-name>
         <access-operations>read</access-operations>
         <action>permit</action>
         <comment>
             Позволяет считывать данные мониторинга NETCONF.
         </comment>
       </rule>
       <rule>
         <name>permit-exec</name>
         <module-name>*</module-name>
         <access-operations>exec</access-operations>
         <action>permit</action>
         <comment>
             Позволяет вызывать поддерживаемые операции сервера.
         </comment>
       </rule>
     </rule-list>

     <rule-list>
       <name>admin-acl</name>
       <group>admin</group>
       <rule>
         <name>permit-all</name>
         <module-name>*</module-name>
         <access-operations>*</access-operations>
         <action>permit</action>
         <comment>
             Дает группе admin полный доступ к операциям и данным.
         </comment>
       </rule>
     </rule-list>
   </nacm>

Этот пример демонстрирует 4 правила:

   deny-ncm: предотвращает доступ группы guest к считыванию данных
      мониторинга в модуле YANG ietf-netconf-monitoring.
   permit-ncm: позволяет группе limited читать модуль YANG
      ietf-netconf-monitoring.
   permit-exec: позволяет группе limited вызывать любые протокольные
      операции, поддерживаемые сервером.
   permit-all: предоставляет группе admin полный доступ к содержимому
      сервера. Далее не будет правил, соответствующих группе admin,
      поскольку это правило для модуля.

A.3. Пример правила для протокольной операции

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

   <nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm">
     <rule-list>
       <name>guest-limited-acl</name>
       <group>limited</group>
       <group>guest</group>
       <rule>
         <name>deny-kill-session</name>
         <module-name>ietf-netconf</module-name>
         <rpc-name>kill-session</rpc-name>
         <access-operations>exec</access-operations>
         <action>deny</action>
         <comment>
           Не позволяет группам limited и guest 'убить' чужую сессию.
         </comment>
       </rule>
       <rule>
         <name>deny-delete-config</name>
         <module-name>ietf-netconf</module-name>
         <rpc-name>delete-config</rpc-name>
         <access-operations>exec</access-operations>
         <action>deny</action>
         <comment>
            Не позволяет группам limited и guest удалять конфигурации.
         </comment>
       </rule>
     </rule-list>

     <rule-list>
       <name>limited-acl</name>
       <group>limited</group>
       <rule>
         <name>permit-edit-config</name>
         <module-name>ietf-netconf</module-name>
         <rpc-name>edit-config</rpc-name>
         <access-operations>exec</access-operations>
         <action>permit</action>
         <comment>
           Позволяет группе limited редактировать конфигурацию.
         </comment>
       </rule>
     </rule-list>
   </nacm>

Этот пример содержит правила для трех операций:

   deny-kill-session: предотвращает вызов группами limited и guest 
      протокольной операции NETCONF <kill-session>.
   deny-delete-config: предотвращает вызов группами limited и guest 
      протокольной операции NETCONF <delete-config>.
   permit-edit-config: разрешает группе limited вызывать операцию
      NETCONF <edit-config>. Это правило не будет работать, пока не
      установлено значение deny для листа exec-default.

A.4. Пример правила для узла данных

Правила узла данных служат для контроля доступа к конкретным (config и non-config) узлам данных в содержимом NETCONF, предоставляемом сервером.

   <nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm">
     <rule-list>
       <name>guest-acl</name>
       <group>guest</group>
       <rule>
         <name>deny-nacm</name>
         <path xmlns:n="urn:ietf:params:xml:ns:yang:ietf-netconf-acm">
           /n:nacm
         </path>
         <access-operations>*</access-operations>
         <action>deny</action>
         <comment>
           Запрет для группы guest доступа к данным /nacm.
         </comment>
       </rule>
     </rule-list>

     <rule-list>
       <name>limited-acl</name>
       <group>limited</group>
       <rule>
         <name>permit-acme-config</name>
         <path xmlns:acme="http://example.com/ns/netconf">
           /acme:acme-netconf/acme:config-parameters
         </path>
         <access-operations>
           read create update delete
         </access-operations>
         <action>permit</action>
         <comment>
           Предоставление группе limited полного доступа к 
           конфигурационным параметрам acme NETCONF. Показана
           длинная форма access-operations вместо сокращенной.
         </comment>
       </rule>
     </rule-list>

     <rule-list>
       <name>guest-limited-acl</name>
       <group>guest</group>
       <group>limited</group>
       <rule>
         <name>permit-dummy-interface</name>
         <path xmlns:acme="http://example.com/ns/itf">
           /acme:interfaces/acme:interface[acme:name='dummy']
         </path>
         <access-operations>read update</access-operations>
         <action>permit</action>
         <comment>
           Разрешает группам limited и guest чтение и обновление
           для интерфейса dummy.
         </comment>
       </rule>
     </rule-list>

     <rule-list>
       <name>admin-acl</name>
       <group>admin</group>
       <rule>
         <name>permit-interface</name>
         <path xmlns:acme="http://example.com/ns/itf">
           /acme:interfaces/acme:interface
         </path>
         <access-operations>*</access-operations>
         <action>permit</action>
         <comment>
           Разрешает группе admin полный доступ к интерфейсам acme.
         </comment>
       </rule>
     </rule-list>
   </nacm>

Этот пример содержит 4 правила для узлов данных:

   deny-nacm: предотвращает доступ группы guest к субдереву /nacm.
   permit-acme-config: разрешает для группы limited доступ read-write
      к acme <config-parameters>.
   permit-dummy-interface: разрешает для групп limited и guest доступ
      read-update к записи acme <interface> с именем dummy. Запись не
      может быть создана или удалена этими группами, можно лишь менять ее.
   permit-interface: дает группе admin доступ read-write ко всем записям
      acme <interface>.

A.5. Пример правила для уведомления

Правила уведомлений служат для контроля доступа к уведомлениям о конкретном типе событий.

   <nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm">
     <rule-list>
       <name>sys-acl</name>
       <group>limited</group>
       <group>guest</group>
       <rule>
         <name>deny-config-change</name>
         <module-name>acme-system</module-name>
         <notification-name>sys-config-change</notification-name>
         <access-operations>read</access-operations>
         <action>deny</action>
         <comment>
           Не позволяет группам guest и limited получать 
           уведомления о смене конфигурации.
         </comment>
       </rule>
     </rule-list>
   </nacm>

Этот пример показывает одно правило для уведомлений:

   deny-config-change: предотвращает отправку в группы limited и
      guest уведомлений о событиях типа acme <sys-config-change>.

Адреса авторов

Andy Bierman

YumaWorks

685 Cochran St.

Suite #160

Simi Valley, CA 93065

United States of America

Email: andy@yumaworks.com

Martin Bjorklund

Tail-f Systems

Email: mbj@tail-f.com


Перевод на русский язык

Николай Малых

nmalykh@gmail.com

1Network Configuration.

2Internet Engineering Task Force.

3Internet Engineering Steering Group.

4Remote Procedure Call — вызов удаленных процедур.

5Create, Read, Update, Delete, eXec — создание, чтение, обновление, удаление, исполнение.

6Secure Shell.

7Man-in-the-middle — перехват и изменение пакетов с участием человека.

8Denial-of-service — отказ в обслуживании.

Рубрика: RFC | Комментарии к записи RFC 8341 Network Configuration Access Control Model отключены

RFC 8346 A YANG Data Model for Layer 3 Topologies

Internet Engineering Task Force (IETF)                          A. Clemm
Request for Comments: 8346                                        Huawei
Category: Standards Track                                      J. Medved
ISSN: 2070-1721                                                    Cisco
                                                                R. Varga
                                               Pantheon Technologies SRO
                                                                  X. Liu
                                                                   Jabil
                                                      H. Ananthakrishnan
                                                           Packet Design
                                                              N. Bahadur
                                                       Bracket Computing
                                                              March 2018

A YANG Data Model for Layer 3 Topologies

Модель данных YANG для топологии L3

PDF

Аннотация

Этот документ определяет модель данных YANG для топологии L3.

Статус документа

Документ относится к категории Internet Standards Track.

Документ является результатом работы IETF1 и представляет согласованный взгляд сообщества IETF. Документ прошёл открытое обсуждение и был одобрен для публикации IESG2. Дополнительную информацию о стандартах Internet можно найти в разделе 2 в RFC 7841.

Информацию о текущем статусе документа, ошибках и способах обратной связи можно найти по ссылке https://www.rfc-editor.org/info/rfc8346.

Авторские права

Copyright (c) 2018. Авторские права принадлежат IETF Trust и лицам, указанным в качестве авторов документа. Все права защищены.

К документу применимы права и ограничения, указанные в BCP 78 и IETF Trust Legal Provisions и относящиеся к документам IETF (http://trustee.ietf.org/license-info), на момент публикации данного документа. Прочтите упомянутые документы внимательно. Фрагменты программного кода, включённые в этот документ, распространяются в соответствии с упрощённой лицензией BSD, как указано в параграфе 4.e документа IETF Trust Legal Provisions, без каких-либо гарантий (как указано в Simplified BSD License).

1. Введение

Этот документ задаёт модель данных YANG [RFC7950] [RFC6991] для сетевой топологии L3, в частности, L3 Unicast. Модель позволяет приложению иметь целостное представление о топологии сети L3 в одном концептуальном хранилище YANG. Модель строится на основе модели данных топологии сети, заданной в [RFC8345], и дополняет ее. Документ также показывает, как можно усовершенствовать модель для охвата разных типов топологии L3 Unicast на примере модели для OSPF [RFC2328]. Пример предназначен для иллюстрации и в полной модели OSPF предполагается большая точность и полнота.

Для модели данных топологии имеется много приложений, варианты использования рассмотрены в разделе 6 [USECASE-REQS]. Например, узлы сети могут применять модель данных для фиксации своего представления топологии сети и раскрывать его сетевому контроллеру. Контроллер может использовать созданные топологические данные для сравнения и согласования со своим видением управляемых элементов сети. Как вариант, узлы сети могут распространять это понимание для сравнения и согласования между собой или с помощью контроллера. Контроллер может даже сам использовать модель данных для представления управляемой им топологии и раскрытия её приложению через свой северный интерфейс.

Заданная в этом документе модель данных для топологии L3 Unicast содержится в модуле YANG ietf-l3-unicast-topology. Этот модуль дополняет общую модель топологии, определённую в [RFC8345], сведениями L3 Unicast. Таким образом, общая топологическая модель расширяется в соответствии с потребностями топологии L3 Unicast.

Сведения, хранящиеся в базе данных организации трафика (Traffic Engineering Database или TED), будут заданы в отдельной модели [YANG-TE] и выходят за рамки этого документа.

2. Уровни требований

Ключевые слова необходимо (MUST), недопустимо (MUST NOT), требуется (REQUIRED), нужно (SHALL), не следует (SHALL NOT), следует (SHOULD), не нужно (SHOULD NOT), рекомендуется (RECOMMENDED), не рекомендуется (NOT RECOMMENDED), возможно (MAY), необязательно (OPTIONAL) в данном документе интерпретируются в соответствии с BCP 14 [RFC2119] [RFC8174] тогда и только тогда, когда они выделены шрифтом, как показано здесь.

3. Определения и сокращения

Этот документ определяет модель YANG и поэтому в нем применяются многие термины, заданные в YANG [RFC7950] и NETCONF [RFC6241]. Некоторые из них, такие как хранилище данных (datastore) и дерево данных (data tree) повторены здесь для ясности и поддержки контекста.

Datastore — хранилище данных

Концептуальное место хранения информации и доступа к ней. Хранилище может быть реализовано с использованием файлов, баз данных, флэш-памяти или их комбинации. Хранилище сопоставляется с созданным экземпляром дерева данных YANG (определение заимствовано из [RFC8342]).

Data subtree — субдерево (ветвь) данных

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

IS-IS

Протокол маршрутизации между промежуточными системами (Intermediate System или IS).

LSP

Label Switched Path — путь с коммутацией по меткам.

NETCONF

Network Configuration Protocol — протокол конфигурации сети.

NMDA

Network Management Datastore Architecture — архитектура хранилища данных управления сетью.

OSPF

Open Shortest Path First — протокол маршрутизации по состояниям каналов.

URI

Uniform Resource Identifier — единый (однотипный) идентификатор ресурса.

TED

Traffic Engineering Database — база данных организации трафика.

YANG

Язык моделирования данных, применяемый в моделях данных конфигурации, состояния, вызовах удалённых процедур (Remote Procedure Call или RPC) и уведомлениях для протоколов управления сетью [RFC7950].

4. Структура модели

Модель для топологии L3 Unicast задана в модуле YANG l3-unicast-topology, связи которого с другими модулями YANG показаны на рисунке 1.

+-----------------------------+
|  +-----------------------+  |
|  |      ietf-network     |  |
|  +----------^------------+  |
|             |               |
|  +-----------------------+  |
|  | ietf-network-topology |  |
|  +----------+------------+  |
+-------------^---------------+
              |
              |
 +------------^-------------+
 | ietf-l3-unicast-topology |
 +------------^-------------+
              |
              |
  +-----------^-----------+
  | example-ospf-topology |
  +-----------------------+

Рисунок 1. Структура модели.


Модули YANG ietf-network и ietf-network-topology совместно задают базовую модель топологии сети [RFC8345]. Модуль YANG ietf-l3-unicast-topology дополняет эту модель определениями, требуемыми для представления топологии L3 Unicast. Сам этот модуль может быть дополнен другими модулями YANG с определениями для конкретных типов топологии L3 Unicast, таких как OSPF и IS-IS.

Модули YANG ietf-network и ietf-network-topology предназначены для совместного применения в реализациях, поддерживающих архитектуру NMDA, определённую в [RFC8342]. Это верно и для модулей YANG, дополняющих их. Для применения модели в ситуациях, где NMDA не поддерживается, в Приложени A определён дополнительный модуль YANG (его не следует применять в реализациях, поддерживающих NMDA).

5. Обзор модели топологии L3 Unicast

Модель топологии L3 Unicast определена в модуле YANG ietf-l3-unicast-topology, а её структура показана ниже в нотации [RFC8340]. Для краткости уведомления не показаны.

   module: ietf-l3-unicast-topology
     augment /nw:networks/nw:network/nw:network-types:
       +--rw l3-unicast-topology!
     augment /nw:networks/nw:network:
       +--rw l3-topology-attributes
          +--rw name?   string
          +--rw flag*   l3-flag-type
     augment /nw:networks/nw:network/nw:node:
       +--rw l3-node-attributes
          +--rw name?        inet:domain-name
          +--rw flag*        node-flag-type
          +--rw router-id*   rt-types:router-id
          +--rw prefix* [prefix]
             +--rw prefix    inet:ip-prefix
             +--rw metric?   uint32
             +--rw flag*     prefix-flag-type
     augment /nw:networks/nw:network/nt:link:
       +--rw l3-link-attributes
          +--rw name?      string
          +--rw flag*      link-flag-type
          +--rw metric1?   uint64
          +--rw metric2?   uint64
     augment /nw:networks/nw:network/nw:node/nt:termination-point:
       +--rw l3-termination-point-attributes
          +--rw (termination-point-type)?
             +--:(ip)
             |  +--rw ip-address*       inet:ip-address
             +--:(unnumbered)
             |  +--rw unnumbered-id?    uint32
             +--:(interface-name)
                +--rw interface-name?   string

Модуль дополняет модули ietf-network и ietf-network-topology, как указано ниже.

  • Добавлен новый тип топологии сети l3-unicast-topology и соответствующий контейнер дополняет типы сетей мз модуля ietf-network.

  • Добавлены атрибуты топологии, определённые в группировке, которая дополняет список network в модуле ietf-network. Атрибуты включают имя топологии и набор флагов в форме leaf-list. Каждый тип флагов представлен своим идентификатором, что позволяет добавлять флаги в модулях дополнения с использованием новых идентификаторов без необходимости перематривать этот модуль.

  • Добавлены объекты данных для узлов путём дополнения списка node в модуле ietf-network. Новые объекты включают набор флагов и список префиксов, каждый из которых содержит префикс IP, метрику и зависящий от префикса набор флагов.

  • Каналы (в ietf-network-topology) дополнены набором параметров, позволяющим связать с каналом имя, набор флагов и метрику.

  • Точки завершения (в ietf-network-topology) дополнены выбором IP-адреса, идентификатора или имени.

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

6. Модуль YANG для топологии L3 Unicast

Этот модуль YANG ссылается на [RFC2863] и [RFC8343].

   <CODE BEGINS> file "ietf-l3-unicast-topology@2018-02-26.yang"
   module ietf-l3-unicast-topology {
     yang-version 1.1;
     namespace
       "urn:ietf:params:xml:ns:yang:ietf-l3-unicast-topology";
     prefix "l3t";
     import ietf-network {
       prefix "nw";
     }
     import ietf-network-topology {
       prefix "nt";
     }

     import ietf-inet-types {
       prefix "inet";
     }
     import ietf-routing-types {
       prefix "rt-types";
     }
     organization
       "IETF I2RS (Interface to the Routing System) Working Group";
     contact
       "WG Web:    <https://datatracker.ietf.org/wg/i2rs/> 
        WG List:   <mailto:i2rs@ietf.org> 
        Editor:    Alexander Clemm
                   <mailto:ludwig@clemm.org> 
        Editor:    Jan Medved
                   <mailto:jmedved@cisco.com> 
        Editor:    Robert Varga
                   <mailto:robert.varga@pantheon.tech> 
        Editor:    Xufeng Liu
                   <mailto:xufeng.liu.ietf@gmail.com> 
        Editor:    Nitin Bahadur
                   <mailto:nitin_bahadur@yahoo.com> 
        Editor:    Hariharan Ananthakrishnan
                   <mailto:hari@packetdesign.com>"; 
     description
       "Модуль определяет модель для топологии L3 Unicast.

        Авторские права (Copyright (c) 2018) принадлежат IETF Trust
        и лицам, указанным в качестве авторов кода. Все права защищены.

        Распространение и использование в исходной или двоичной форме с
        изменениями или без таковых разрешено в соответствии с лицензией
        Simplified BSD, изложенной в разделе 4  IETF Trust's Legal
        Provisions применительно к документам IETF
        (http://trustee.ietf.org/license-info). 
 
        Эта версия данного модуля YANG является частью RFC 8346, где
        правовые вопросы рассмотрены более полно.";
     revision "2018-02-26" {
       description
         "Initial revision.";
       reference
         "RFC 8346: A YANG Data Model for Layer 3 Topologies";
     }

     identity flag-identity {
       description "Базовый тип для флагов.";
     }

     typedef l3-event-type {
       type enumeration {
         enum "add" {
           description
             "Добавлен узел, канал, префикс или точка завершения L3.";
         }
         enum "remove" {
           description
             "Удален узел, канал, префикс или точка завершения L3.";
         }
         enum "update" {
           description
             "Обновлен узел, канал, префикс или точка завершения L3.";
         }
       }
       description "Тип события L3 для уведомлений.";
     }

     typedef prefix-flag-type {
       type identityref {
         base "flag-identity";
       }
       description "Атрибуты флагов префикса.";
     }

     typedef node-flag-type {
       type identityref {
         base "flag-identity";
       }
       description "Атрибуты флагов узла.";
     }

     typedef link-flag-type {
       type identityref {
         base "flag-identity";
       }
       description "Атрибуты флагов канала.";
     }

     typedef l3-flag-type {
       type identityref {
         base "flag-identity";
       }
       description "Атрибуты флагов L3.";
     }

     grouping l3-prefix-attributes {
       description
         "Атрибуты префикса L3.";
       leaf prefix {
         type inet:ip-prefix;
         description
           "Префикс IP.";
       }
       leaf metric {
         type uint32;
         description
           "Метрика префикса.";
       }
       leaf-list flag {
         type prefix-flag-type;
         description
           "Флаги префикса.";
       }
     }
     grouping l3-unicast-topology-type {
       description "Указывает тип топологии L3 Unicast.";
       container l3-unicast-topology {
         presence "Указывает тип топологии L3 Unicast.";
         description
           "Наличие контейнера указывает топологию L3 Unicast";
       }
     }
     grouping l3-topology-attributes {
       description "Атрибуты области действия топологии.";
       container l3-topology-attributes {
         description "Атрибуты топологии.";
         leaf name {
           type string;
           description
             "Имя топологии.";
         }
         leaf-list flag {
           type l3-flag-type;
           description
             "Флаги топологии.";
         }
       }
     }
     grouping l3-node-attributes {
       description "Атрибуты области действия узла L3.";
       container l3-node-attributes {
         description
           "Атрибуты узла";
         leaf name {
           type inet:domain-name;
           description
             "Имя узла.";
         }
         leaf-list flag {
           type node-flag-type;
           description
             "Флаги узла.";
         }
         leaf-list router-id {
           type rt-types:router-id;
           description
             "Router-id для узла.";
         }
         list prefix {
           key "prefix";
           description
             "Список префиксов с их атрибутами.";
           uses l3-prefix-attributes;
         }
       }
     }
     grouping l3-link-attributes {
       description
         "Атрибуты области действия канала L3.";
       container l3-link-attributes {
         description
           "Атрибуты канала.";
         leaf name {
           type string;
           description
             "Имя канала.";
         }
         leaf-list flag {
           type link-flag-type;
           description
             "Флаги канала.";
         }
         leaf metric1 {
           type uint64;
           description
               "Метрика 1 для канала.";
         }
         leaf metric2 {
           type uint64;
           description
               "Метрика 2 для канала.";
         }
       }
     }
     grouping l3-termination-point-attributes {
       description "Атрибуты области действия точки завершения L3.";
       container l3-termination-point-attributes {
         description
           "Атрибуты точки завершения.";
         choice termination-point-type {
           description
             "Тип точки завершения.";
           case ip {
             leaf-list ip-address {
               type inet:ip-address;
               description
                 "Адрес IPv4 или IPv6.";
             }
           }
           case unnumbered {
             leaf unnumbered-id {
               type uint32;
               description
                 "Идентификатор безадресного интерфейса, соответствующий
                  значению ifIndex для интерфейса, т. е. ifIndex для
                  узла ifEntry, представляющего интерфейс в реализации с
                  поддержкой Interfaces Group MIB (RFC 2863).";
               reference
                 "RFC 2863: The Interfaces Group MIB";
             }
           }
           case interface-name {
             leaf interface-name {
               type string;
               description
                 "Имя интерфейса, которое может (но не обязано)
                  соответствовать ссылке на интерфейс содержащего его
                  узла, т. е. путь к соответствующему узлу данных
                  интерфейса на содержащем его узле напоминает тип
                  данных interface-ref из RFC 8343. Следует отметить, 
                  что тип interface-ref из RFC 8343 нельзя применять
                  напрямую, поскольку он служит для указания интерфейса
                  в хранилище данных одного узла сети, а не для 
                  однозначного указания интерфейсов всей сети.";
               reference
                 "RFC 8343: A YANG Data Model for Interface Management";
             }
           }
         }
       }
     }
     augment "/nw:networks/nw:network/nw:network-types" {
       description
         "Новый тип сети для топологии L3 Unicast";
       uses l3-unicast-topology-type;
     }
     augment "/nw:networks/nw:network" {
       when "nw:network-types/l3t:l3-unicast-topology" {
         description
           "Параметры дополнения, применимые лишь для сетей с топологией
            L3 Unicast.";
       }
       description
           "L3 Unicast для сети в целом.";
       uses l3-topology-attributes;
     }
     augment "/nw:networks/nw:network/nw:node" {
       when "../nw:network-types/l3t:l3-unicast-topology" {
         description
           "Параметры дополнения, применимые лишь для сетей с топологией
            L3 Unicast.";
       }
       description
           "Атрибуты на уровне узлаL3 Unicast.";
       uses l3-node-attributes;
     }
     augment "/nw:networks/nw:network/nt:link" {
       when "../nw:network-types/l3t:l3-unicast-topology" {
         description
           "Параметры дополнения, применимые лишь для сетей с топологией
            L3 Unicast.";
       }
       description
         "Дополнение атрибутов топологического канала.";
       uses l3-link-attributes;
     }
     augment "/nw:networks/nw:network/nw:node/"
            +"nt:termination-point" {
       when "../../nw:network-types/l3t:l3-unicast-topology" {
         description
           "Параметры дополнения, применимые лишь для сетей с топологией
            L3 Unicast.";
       }
       description "Дополнение конфигурации топологии точки завершения";
       uses l3-termination-point-attributes;
     }
     notification l3-node-event {
       description
         "Уведомление о событии для узла L3.";
       leaf l3-event-type {
         type l3-event-type;
         description
           "Тип события";
       }
       uses nw:node-ref;
       uses l3-unicast-topology-type;
       uses l3-node-attributes;
     }
     notification l3-link-event {
       description
         "Уведомление о событии для канала L3.";
       leaf l3-event-type {
         type l3-event-type;
         description
           "Тип события";
       }
       uses nt:link-ref;
       uses l3-unicast-topology-type;
       uses l3-link-attributes;
     }
     notification l3-prefix-event {
       description
         "Уведомление о событии для префикса L3.";
       leaf l3-event-type {
         type l3-event-type;
         description
           "Тип события";
       }
       uses nw:node-ref;
       uses l3-unicast-topology-type;
       container prefix {
         description
           "Атрибуты префикса L3.";
         uses l3-prefix-attributes;
       }
     }
     notification termination-point-event {
       description
         "Уведомление о событии для точки завершения L3.";
       leaf l3-event-type {
         type l3-event-type;
         description
           "Тип события";
       }
       uses nt:tp-ref;
       uses l3-unicast-topology-type;
       uses l3-termination-point-attributes;
     }
   }
   <CODE ENDS>

7. Взаимодействия с другими модулями YANG

Как указано в разделе 4, модель в этом документе основана на модулях YANG из [RFC8345] и дополняет их. В частности, модуль ietf-l3-unicast-topology дополняет модули ietf-network и ietf-network-topology. Кроме того, модель использует типы данных, определённые в [RFC6991].

Модель является независимой от протокола моделью данных YANG со сведениями о топологии L3. Она отделена и не связана с моделями данных, применяемыми для настройки протоколов или данных маршрутизации, такими как ietf-routing [RFC8022] и ietf-rib-extension [YANG-RIB]. При этом модель импортирует определение типа из ietf-routing-types [RFC8294].

Модель соответствует требованиям к эфемерному состоянию из [RFC8242]. Для эфемерных данных топологии, предоставляемых сервером, процесс, которому поручено поддерживать сведения о топологии, будет загружать данные из процесса маршрутизации (например, OSPF) в модель данных, не полагаясь на хранилище данных конфигурации.

8. Взаимодействие с IANA

Этот документ регистрирует два идентификатора URI в реестре IETF XML Registry [RFC3688].

   URI: urn:ietf:params:xml:ns:yang:ietf-l3-unicast-topology
   Registrant Contact: The IESG.
   XML: N/A; запрошенный URI является пространством имён XML.

   URI: urn:ietf:params:xml:ns:yang:ietf-l3-unicast-topology-state
   Registrant Contact: The IESG.
   XML: N/A; запрошенный URI является пространством имён XML.

Документ регистрирует два модуля YANG в реестре YANG Module Names [RFC6020].

   Name: ietf-l3-unicast-topology
   Namespace: urn:ietf:params:xml:ns:yang:ietf-l3-unicast-topology
   Prefix: l3t
   Reference: RFC 8346

   Name: ietf-l3-unicast-topology-state
   Namespace: urn:ietf:params:xml:ns:yang:ietf-l3-unicast-topology-state
   Prefix: l3t-s
   Reference: RFC 8346

9. Вопросы безопасности

Заданные в этом документе модули YANG определяют схемы для данных, которые разработаны для доступа через протоколы управления сетью, такие как NETCONF [RFC6241] и RESTCONF [RFC8040]. Нижним уровнем NETCONF является защищённый транспорт с обязательной реализацией Secure Shell (SSH) [RFC6242]. Нижним уровнем RESTCONF служит HTTPS с обязательной реализацией защищённого транспорта TLS [RFC5246].

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

Обычно топология L3 Unicast контролируется системой и обеспечивает эфемерные топологические данные. На серверах NMDA это лишь часть рабочего хранилища <operational>, обеспчающая клиентам доступ только для чтения, поэтому они менее уязвимы. Тем не менее, эти модули YANG в принципе позволяют настраивать данные.

В модулях YANG имеется множество узлов данных, доступных для записи, создания, удаления (т. е. с принятым по умолчанию config true). Эти узлы могут быть чувствительными или уязвимыми в некоторых сетевых средах. Операции записи (например, edit-config) в такие узлы без подобающей защиты могут оказывать негативное влияние на работу сети. Ниже указаны ветви и узлы данных модуля ietf-l3-unicast-topology с их уязвимостями.

l3-topology-attributes

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

l3-node-attributes

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

l3-link-attributes

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

l3-termination-point-attributes

Враждебный клиент может попытаться саботировать настройку точки завершения, например её адреса IP и имени.

10. Литература

10.1. Нормативные документы

[RFC2119] Bradner, S., «Key words for use in RFCs to Indicate Requirement Levels», BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, <https://www.rfc-editor.org/info/rfc2119>.

[RFC2328] Moy, J., «OSPF Version 2», STD 54, RFC 2328, DOI 10.17487/RFC2328, April 1998, <https://www.rfc-editor.org/info/rfc2328>.

[RFC2863] McCloghrie, K. and F. Kastenholz, «The Interfaces Group MIB», RFC 2863, DOI 10.17487/RFC2863, June 2000, <https://www.rfc-editor.org/info/rfc2863>.

[RFC3688] Mealling, M., «The IETF XML Registry», BCP 81, RFC 3688, DOI 10.17487/RFC3688, January 2004, <https://www.rfc-editor.org/info/rfc3688>.

[RFC5246] Dierks, T. and E. Rescorla, «The Transport Layer Security (TLS) Protocol Version 1.2», RFC 5246, DOI 10.17487/RFC5246, August 2008, <https://www.rfc-editor.org/info/rfc5246>.

[RFC6020] Bjorklund, M., Ed., «YANG — A Data Modeling Language for the Network Configuration Protocol (NETCONF)», RFC 6020, DOI 10.17487/RFC6020, October 2010, <https://www.rfc-editor.org/info/rfc6020>.

[RFC6241] Enns, R., Ed., Bjorklund, M., Ed., Schoenwaelder, J., Ed., and A. Bierman, Ed., «Network Configuration Protocol (NETCONF)», RFC 6241, DOI 10.17487/RFC6241, June 2011, <https://www.rfc-editor.org/info/rfc6241>.

[RFC6242] Wasserman, M., «Using the NETCONF Protocol over Secure Shell (SSH)», RFC 6242, DOI 10.17487/RFC6242, June 2011, <https://www.rfc-editor.org/info/rfc6242>.

[RFC6991] Schoenwaelder, J., Ed., «Common YANG Data Types», RFC 6991, DOI 10.17487/RFC6991, July 2013, <https://www.rfc-editor.org/info/rfc6991>.

[RFC7950] Bjorklund, M., Ed., «The YANG 1.1 Data Modeling Language», RFC 7950, DOI 10.17487/RFC7950, August 2016, <https://www.rfc-editor.org/info/rfc7950>.

[RFC7951] Lhotka, L., «JSON Encoding of Data Modeled with YANG», RFC 7951, DOI 10.17487/RFC7951, August 2016, <https://www.rfc-editor.org/info/rfc7951>.

[RFC8040] Bierman, A., Bjorklund, M., and K. Watsen, «RESTCONF Protocol», RFC 8040, DOI 10.17487/RFC8040, January 2017, <https://www.rfc-editor.org/info/rfc8040>.

[RFC8174] Leiba, B., «Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words», BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017, <https://www.rfc-editor.org/info/rfc8174>.

[RFC8294] Liu, X., Qu, Y., Lindem, A., Hopps, C., and L. Berger, «Common YANG Data Types for the Routing Area», RFC 8294, DOI 10.17487/RFC8294, December 2017, <https://www.rfc-editor.org/info/rfc8294>.

[RFC8341] Bierman, A. and M. Bjorklund, «Network Configuration Access Control Model», STD 91, RFC 8341, DOI 10.17487/RFC8341, March 2018, <https://www.rfc-editor.org/info/rfc8341>.

[RFC8342] Bjorklund, M., Schoenwaelder, J., Shafer, P., Watsen, K., and R. Wilton, «Network Management Datastore Architecture (NMDA)», RFC 8342, DOI 10.17487/RFC8342, March 2018, <https://www.rfc-editor.org/info/rfc8342>.

[RFC8345] Clemm, A., Medved, J., Varga, R., Bahadur, N., Ananthakrishnan, H., and X. Liu, «A YANG Data Model for Network Topologies», RFC 8345, DOI 10.17487/RFC8345, March 2018, <https://www.rfc-editor.org/info/rfc8345>.

10.2. Дополнительная литература

[RFC8022] Lhotka, L. and A. Lindem, «A YANG Data Model for Routing Management», RFC 8022, DOI 10.17487/RFC8022, November 2016, <https://www.rfc-editor.org/info/rfc8022>.

[RFC8242] Haas, J. and S. Hares, «Interface to the Routing System (I2RS) Ephemeral State Requirements», RFC 8242, DOI 10.17487/RFC8242, September 2017, <https://www.rfc-editor.org/info/rfc8242>.

[RFC8340] Bjorklund, M. and L. Berger, Ed., «YANG Tree Diagrams», BCP 215, RFC 8340, DOI 10.17487/RFC8340, March 2018, <https://www.rfc-editor.org/info/rfc8340>.

[RFC8343] Bjorklund, M., «A YANG Data Model for Interface Management», RFC 8343, DOI 10.17487/RFC8343, March 2018, <https://www.rfc-editor.org/info/rfc8343>.

[USECASE-REQS] Hares, S. and M. Chen, «Summary of I2RS Use Case Requirements», Work in Progress, draft-ietf-i2rs-usecase-reqs-summary-03, November 2016.

[YANG-RIB] Lindem, A. and Y. Qu, «RIB YANG Data Model», Work in Progress, draft-acee-rtgwg-yang-rib-extend-06, January 2018.

[YANG-TE] Liu, X., Bryskin, I., Beeram, V., Saad, T., Shah, H., and O. Gonzalez de Dios, «YANG Data Model for Traffic Engineering (TE) Topologies», Work in Progress, draft-ietf-teas-yang-te-topo-153, February 2018.

Приложение A. Модель YANG для реализаций без NMDA

Определённый здесь модуль YANG ietf-l3-unicast-topology дополняет модули ietf-network и ietf-network-topology из [RFC8345], предназначенные для использования с реализациями, поддерживающими архитектуру NMDA [RFC8342]. Для возможности применения этой модели без поддержки NMDA в [RFC8345] заданы два дополнительных модуля ietf-network-state и ietf-network-topology-state, представляющие модели состояния сетей и сетевой топологии.

Для возможности применения заданной здесь модели для топологии L3 в реализациях без поддержки NMDA нужен дополнительный модуль. Этот модуль ietf-l3-unicast-topology-state отражает ietf-l3-unicast-topology и дополняет модули ietf-network-state и ietf-network-topology-state (вместо ietf-network и ietf-network-topology), а все его узлы являются ненастраиваемыми.

Похожие соображения применимы к любому модулю, дополняющему ietf-l3- unicast-topology, такому как пример из приложения B (example-ospf-topology). Для реализаций, не поддерживающих NMDA, нужны дополнительные модули, представляющие данные состояния и не содержащие настраиваемых узлов. Эти модули дополняют ietf-l3-unicast-topology-state, а не ietf-l3-unicast-topology. Дополнительные модули для модуля из приложения B не представлены здесь, поскольку этот модуль служит лишь примером.

Подобно ietf-network-state и ietf-network-topology-state, модуль ietf-l3-unicast-topology не следует поддерживать реализациям с NMDA. Поэтому модуль вынесен в приложение. Определение модуля приведено ниже, а его структура соответствует структуре базового модуля и не показана для краткости.

   <CODE BEGINS> file "ietf-l3-unicast-topology-state@2018-02-26.yang"
   module ietf-l3-unicast-topology-state {
     yang-version 1.1;
     namespace
       "urn:ietf:params:xml:ns:yang:ietf-l3-unicast-topology-state";
     prefix "l3t-s";
     import ietf-network-state {
       prefix "nw-s";
     }
     import ietf-network-topology-state {
       prefix "nt-s";
     }
     import ietf-l3-unicast-topology {
       prefix "l3t";
     }
     organization
       "IETF I2RS (Interface to the Routing System) Working Group";
     contact
       "WG Web:    <https://datatracker.ietf.org/wg/i2rs/> 
        WG List:   <mailto:i2rs@ietf.org> 
        Editor:    Alexander Clemm
                   <mailto:ludwig@clemm.org> 
        Editor:    Jan Medved
                   <mailto:jmedved@cisco.com> 
        Editor:    Robert Varga
                   <mailto:robert.varga@pantheon.tech> 
        Editor:    Xufeng Liu
                   <mailto:xufeng.liu.ietf@gmail.com> 
        Editor:    Nitin Bahadur
                   <mailto:nitin_bahadur@yahoo.com> 
        Editor:    Hariharan Ananthakrishnan
                   <mailto:hari@packetdesign.com>"; 
     description
       "Этот модуль определяет модель состояния топологии L3 Unicast, 
        представляя топологию, которая изучена или является результатом
        применения топологии, заданной моделью ietf-l3-unicast-topology,
        отражающей соответствующие узлы этой модели.

        Модель отражает ietf-l3-unicast-topology, но содержит доступные
        лишь для чтения данные состояния. Модель не предназначена для
        случаев, когда базовая инфраструктура поддерживает NMDA.

        Авторские права (Copyright (c) 2018) принадлежат IETF Trust
        и лицам, указанным в качестве авторов кода. Все права защищены.

        Распространение и использование в исходной или двоичной форме с
        изменениями или без таковых разрешено в соответствии с лицензией
        Simplified BSD, изложенной в разделе 4  IETF Trust's Legal
        Provisions применительно к документам IETF
        (http://trustee.ietf.org/license-info). 
 
        Эта версия данного модуля YANG является частью RFC 8346, где
        правовые вопросы рассмотрены более полно.";
     revision "2018-02-26" {
       description
         "Исходный выпуск.";
       reference
         "RFC 8346: A YANG Data Model for Layer 3 Topologies";
     }
     augment "/nw-s:networks/nw-s:network/nw-s:network-types" {
       description
         "Новый тип сети для топологии L3 Unicast";
       uses l3t:l3-unicast-topology-type;
     }
     augment "/nw-s:networks/nw-s:network" {
       when "nw-s:network-types/l3t-s:l3-unicast-topology" {
         description
           "Параметры дополнения, применимые лишь для сетей с топологией
            L3 Unicast.";
       }
       description
           "L3 Unicast для сети в целом.";
       uses l3t:l3-topology-attributes;
     }
     augment "/nw-s:networks/nw-s:network/nw-s:node" {
       when "../nw-s:network-types/l3t-s:l3-unicast-topology" {
         description
           "Параметры дополнения, применимые лишь для сетей с топологией
            L3 Unicast.";
       }
       description
           "Атрибуты L3 Unicast на уровне узла.";
       uses l3t:l3-node-attributes;
     }
     augment "/nw-s:networks/nw-s:network/nt-s:link" {
       when "../nw-s:network-types/l3t-s:l3-unicast-topology" {
         description
           "Параметры дополнения, применимые лишь для сетей с топологией
            L3 Unicast.";
       }
       description
         "Дополнение атрибутов топологии канала.";
       uses l3t:l3-link-attributes;
     }
     augment "/nw-s:networks/nw-s:network/nw-s:node/"
            +"nt-s:termination-point" {
       when "../../nw-s:network-types/l3t-s:l3-unicast-topology" {
         description
           "Параметры дополнения, применимые лишь для сетей с топологией
            L3 Unicast.";
       }
       description "Дополняет конфигурацию точки завершения.";
       uses l3t:l3-termination-point-attributes;
     }
     notification l3-node-event {
       description
         "Уведомление о событии для узла L3.";
       leaf l3-event-type {
         type l3t:l3-event-type;
         description
           "Тип события";
       }
       uses nw-s:node-ref;
       uses l3t:l3-unicast-topology-type;
       uses l3t:l3-node-attributes;
     }
     notification l3-link-event {
       description
         "Уведомление о событии для канала L3.";
       leaf l3-event-type {
         type l3t:l3-event-type;
         description
           "Тип события";
       }
       uses nt-s:link-ref;
       uses l3t:l3-unicast-topology-type;
       uses l3t:l3-link-attributes;
     }
     notification l3-prefix-event {
       description
         "Уведомление о событии для префикса L3.";
       leaf l3-event-type {
         type l3t:l3-event-type;
         description
           "Тип события";
       }
       uses nw-s:node-ref;
       uses l3t:l3-unicast-topology-type;
       container prefix {
         description
           "Атрибуты префикса L3";
         uses l3t:l3-prefix-attributes;
       }
     }
     notification termination-point-event {
       description
         "Уведомление о событии для точки завершения L3.";
       leaf l3-event-type {
         type l3t:l3-event-type;
         description
           "Тип события";
       }
       uses nt-s:tp-ref;
       uses l3t:l3-unicast-topology-type;
       uses l3t:l3-termination-point-attributes;
     }
   }
   <CODE ENDS>

Приложение B. Расширение модели

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

B.1. Пример топологии OSPF

B.1.1. Обзор модели

Приведённая ниже модель показывает как можно расширить модель топологии L3 Unicast для OSPF, путём набора дополнений в модуле YANG example-ospf-topology, структура которого показана ниже (в нотации [RFC8340]). Отметим, что одна строка разделена на 2 части, поскольку её размер превышал 72 символа, принятые в RFC.

   module: example-ospf-topology
   augment /nw:networks/nw:network/nw:network-types/
     l3t:l3-unicast-topology:
     +--rw ospf!
   augment /nw:networks/nw:network/l3t:l3-topology-attributes:
     +--rw ospf-topology-attributes
        +--rw area-id?   area-id-type
   augment /nw:networks/nw:network/nw:node/l3t:l3-node-attributes:
     +--rw ospf-node-attributes
        +--rw (router-type)?
        |  +--:(abr)
        |  |  +--rw abr?               empty
        |  +--:(asbr)
        |  |  +--rw asbr?              empty
        |  +--:(internal)
        |  |  +--rw internal?          empty
        |  +--:(pseudonode)
        |     +--rw pseudonode?        empty
        +--rw dr-interface-id?   uint32
   augment /nw:networks/nw:network/nt:link/l3t:l3-link-attributes:
     +--rw ospf-link-attributes
   augment /l3t:l3-node-event:
     +---- ospf!
     +---- ospf-node-attributes
        +---- (router-type)?
        |  +--:(abr)
        |  |  +---- abr?               empty
        |  +--:(asbr)
        |  |  +---- asbr?              empty
        |  +--:(internal)
        |  |  +---- internal?          empty
        |  +--:(pseudonode)
        |     +---- pseudonode?        empty
        +---- dr-interface-id?   uint32
   augment /l3t:l3-link-event:
     +---- ospf!
     +---- ospf-link-attributes

Модуль дополняет ietf-l3-unicast-topology, как показано ниже.

  • Добавлен новый тип для топологии OSPF.

  • Заданы дополнительные атрибуты топологии в новой группировке, которая дополняет l3-topology-attributes из модуля ietf-l3-unicast-topology. Атрибуты включают OSPF area-id для указания области OSPF.

  • Заданы дополнительные объекты для узлов путём дополнения l3-node-attributes из модуля ietf-l3-unicast-topology. Новые объекты включают router-type и dr-interface-id для псевдоузлов.

  • Каналы дополнены атрибутами каналов OSPF.

Кроме того, модуль добавляет уведомления для событий, связанных с узлами L3 и каналы с атрибутами OSPF.

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

B.1.2. Модуль YANG для топологии OSPF

Модуль YANG OSPF Topology представлен ниже. Как уже отмечено, он служит лишь примером расширения модели топологии L3 Unicast для OSPF и не является нормативным. Поэтому модуль приведён без тегов <CODE BEGINS> и <CODE ENDS>.

  file "example-ospf-topology@2017-12-16.yang"
  module example-ospf-topology {
      yang-version 1.1;
      namespace "urn:example:example-ospf-topology";
      prefix "ex-ospft";
      import ietf-yang-types {
          prefix "yang";
      }
      import ietf-network {
          prefix "nw";
      }
      import ietf-network-topology {
          prefix "nt";
      }
      import ietf-l3-unicast-topology {
          prefix "l3t";
      }
      description
         "Этот модуль служит примером расширения топологии 
          Layer 3 Unicast для OSPF.";
      typedef area-id-type {
          type yang:dotted-quad;
          description
              "Тип Area ID.";
      }
      grouping ospf-topology-type {
          description
              "Указывает тип топологии OSPF.";
          container ospf {
              presence "Указывает топологию OSPF.";
              description
                  "Присутствие говорит о топологии типа OSPF.";
          }
      }
      augment "/nw:networks/nw:network/nw:network-types/"
      + "l3t:l3-unicast-topology" {
          description
              "Определяет тип топологии OSPF.";
          uses ospf-topology-type;
      }
      augment "/nw:networks/nw:network/l3t:l3-topology-attributes" {
          when "../nw:network-types/l3t:l3-unicast-topology/" +
              "ex-ospft:ospf" {
              description
                  "Дополняет лишь топологию OSPF.";
              }
          description
              "Дополняет конфигурацию топологии.";
          container ospf-topology-attributes {
              description
                  "Атрибуты топологии.";
              leaf area-id {
                  type area-id-type;
                  description
                      "Идентификатор области OSPF.";
              }
          }
      }
      augment "/nw:networks/nw:network/nw:node/l3t:l3-node-attributes" {
          when "../../nw:network-types/l3t:l3-unicast-topology/" +
              "ex-ospft:ospf" {
              description
                  "Дополняет лишь топологию OSPF.";
          }
          description
              "Дополняет конфигурацию узла.";
          uses ospf-node-attributes;
      }
      augment "/nw:networks/nw:network/nt:link/l3t:l3-link-attributes" {
          when "../../nw:network-types/l3t:l3-unicast-topology/" +
              "ex-ospft:ospf" {
              description
                  "Дополняет лишь топологию OSPF.";
          }
          description
              "Дополняет конфигурацию канала.";
          uses ospf-link-attributes;
      }
      grouping ospf-node-attributes {
          description
              "Дополняет атрибуты области действия узла OSPF.";
          container ospf-node-attributes {
              description
                  "Атрибуты узла.";
              choice router-type {
                  description
                      "Тип маршрутизатора.";
                  case abr {
                      leaf abr {
                          type empty;
                          description
                              "Узел является ABR";
                      }
                  }
                  case asbr {
                      leaf asbr {
                          type empty;
                          description
                              "Узел является ASBR";
                      }
                  }
                  case internal {
                      leaf internal {
                          type empty;
                          description
                              "Узел является внутренним";
                      }
                  }
                  case pseudonode {
                      leaf pseudonode {
                          type empty;
                          description
                              "Псевдоузел.";
                      }
                  }
              }
              leaf dr-interface-id {
                  when "../pseudonode" {
                      description
                          "Действителен лишь для псевдоузла.";
                  }
                  type uint32;
                  default "0";
                  description
                      "DR interface-id для псевдоузлов.";
              }
          }
      }
      grouping ospf-link-attributes {
          description
              "Атрибуты области действия канала OSPF.";
          container ospf-link-attributes {
              description
                  "Атрибуты канала OSPF.";
          }
      } // ospf-link-attributes
      augment "/l3t:l3-node-event" {
          description
              "Событие на узле OSPF.";
          uses ospf-topology-type;
          uses ospf-node-attributes;
      }
      augment "/l3t:l3-link-event" {
          description
              "Событие на канале OSPF.";
          uses ospf-topology-type;
          uses ospf-link-attributes;
      }
  }

Приложение C. Пример

В этом приложении представлен пример дерева данных с кодированием JSON [RFC7951]. Пример создаёт экземпляр ietf-l3-unicast-topology для топологии, показанной на рисунке 2. Здесь имеется три узла: D1, D2, D3. Узел D1 имеет три точки завершения 1-0-1, 1-2-1, 1-3-1, D2 — 2-1-1, 2-0-1, 2-3-1, а D3 — две точки завершения 3-1-1 и 3-2-1. Имеется также 6 каналов, по два между каждой парой узлов с одним каналом для каждого направления.

 +------------+                   +------------+
 |     D1     |                   |     D2     |
/-\          /-\                 /-\          /-\
| | 1-0-1    | |---------------->| | 2-1-1    | |
| |    1-2-1 | |<----------------| |    2-0-1 | |
\-/  1-3-1   \-/                 \-/  2-3-1   \-/
 |   /----\   |                   |   /----\   |
 +---|    |---+                   +---|    |---+
     \----/                           \----/
      A  |                             A  |
      |  |                             |  |
      |  |                             |  |
      |  |       +------------+        |  |
      |  |       |     D3     |        |  |
      |  |      /-\          /-\       |  |
      |  +----->| | 3-1-1    | |-------+  |
      +---------| |    3-2-1 | |<---------+
                \-/          \-/
                 |            |
                 +------------+

Рисунок 2. Пример топологии сети.


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

   {
     "ietf-network:networks": {
       "network": [
         {
           "network-types": {
             "ietf-l3-unicast-topology:l3-unicast-topology": {}
           },
           "network-id": "l3-topo-example",
           "node": [
             {
               "node-id": "D1",
               "termination-point": [
                 {
                   "tp-id": "1-0-1",
                   "ietf-l3-unicast-topology:
                     l3-termination-point-attributes": {
                     "unnumbered-id:": 101
                   }
                 },
                 {
                   "tp-id": "1-2-1",
                   "ietf-l3-unicast-topology:
                     l3-termination-point-attributes": {
                     "unnumbered-id:": 121
                   }
                 },
                 {
                   "tp-id": "1-3-1",
                   "ietf-l3-unicast-topology:
                     l3-termination-point-attributes": {
                     "unnumbered-id:": 131
                   }
                 }
               ],
               "ietf-l3-unicast-topology:l3-node-attributes": {
                 "router-id": ["203.0.113.1"]
               }
             },
             {
               "node-id": "D2",
               "termination-point": [
                 {
                   "tp-id": "2-0-1",
                   "ietf-l3-unicast-topology:
                     l3-termination-point-attributes": {
                     "unnumbered-id:": 201
                   }
                 },
                 {
                   "tp-id": "2-1-1",
                   "ietf-l3-unicast-topology:
                     l3-termination-point-attributes": {
                     "unnumbered-id:": 211
                   }
                 },
                 {
                   "tp-id": "2-3-1",
                   "ietf-l3-unicast-topology:
                     l3-termination-point-attributes": {
                     "unnumbered-id:": 231
                   }
                 }
               ],
               "ietf-l3-unicast-topology:l3-node-attributes": {
                 "router-id": ["203.0.113.2"]
               }
             },
             {
               "node-id": "D3",
               "termination-point": [
                 {
                   "tp-id": "3-1-1",
                   "ietf-l3-unicast-topology:
                     l3-termination-point-attributes": {
                     "unnumbered-id:": 311
                   }
                 },
                 {
                   "tp-id": "3-2-1",
                   "ietf-l3-unicast-topology:
                     l3-termination-point-attributes": {
                     "unnumbered-id:": 321
                   }
                 }
               ],
               "ietf-l3-unicast-topology:l3-node-attributes": {
                 "router-id": ["203.0.113.3"]
               }
             }
           ],
           "ietf-network-topology:link": [
             {
               "link-id": "D1,1-2-1,D2,2-1-1",
               "source": {
                 "source-node": "D1",
                 "source-tp": "1-2-1"
               }
               "destination": {
                 "dest-node": "D2",
                 "dest-tp": "2-1-1"
               },
               "ietf-l3-unicast-topology:l3-link-attributes": {
                 "metric1": "100"
               }
             },
             {
               "link-id": "D2,2-1-1,D1,1-2-1",
               "source": {
                 "source-node": "D2",
                 "source-tp": "2-1-1"
               }
               "destination": {
                 "dest-node": "D1",
                 "dest-tp": "1-2-1"
               },
               "ietf-l3-unicast-topology:l3-link-attributes": {
                 "metric1": "100"
               }
             },
             {
               "link-id": "D1,1-3-1,D3,3-1-1",
               "source": {
                 "source-node": "D1",
                 "source-tp": "1-3-1"
               }
               "destination": {
                 "dest-node": "D3",
                 "dest-tp": "3-1-1"
               },
               "ietf-l3-unicast-topology:l3-link-attributes": {
                 "metric1": "100"
               }
             },
             {
               "link-id": "D3,3-1-1,D1,1-3-1",
               "source": {
                 "source-node": "D3",
                 "source-tp": "3-1-1"
               }
               "destination": {
                 "dest-node": "D1",
                 "dest-tp": "1-3-1"
               },
               "ietf-l3-unicast-topology:l3-link-attributes": {
                 "metric1": "100"
               }
             },
             {
               "link-id": "D2,2-3-1,D3,3-2-1",
               "source": {
                 "source-node": "D2",
                 "source-tp": "2-3-1"
               }
               "destination": {
                 "dest-node": "D3",
                 "dest-tp": "3-2-1"
               },
               "ietf-l3-unicast-topology:l3-link-attributes": {
                 "metric1": "100"
               }
             },
             {
               "link-id": "D3,3-2-1,D2,2-3-1",
               "source": {
                 "source-node": "D3",
                 "source-tp": "3-2-1"
               }
               "destination": {
                 "dest-node": "D2",
                 "dest-tp": "2-3-1"
               },
               "ietf-l3-unicast-topology:l3-link-attributes": {
                 "metric1": "100"
               }
             }
           ]
         }
       ]
     }
   }

Рисунок 3. Дерево данных экземпляра.

Благодарности

Спасибо Alia Atlas, Andy Bierman, Benoit Claise, Joel Halpern, Susan Hares, Ladislav Lhotka, Carl Moberg, Carlos Pignataro, Juergen Schoenwaelder, Michal Vasco, Kent Watsen за полезный вклад, комментарии и предложения.

Участники работы

В разработке представленной в документе модели участвовало больше людей, нежели указано в списке авторов. Дополнительные участники работы перечислены ниже.

  • Vishnu Pavan Beeram, Juniper
  • Igor Bryskin, Huawei
  • Ken Gray, Cisco
  • Aihua Guo, Huawei
  • Tom Nadeau, Brocade
  • Tony Tkacik
  • Aleksandr Zhdankin, Cisco

Адреса авторов

Alexander Clemm
Huawei USA — Futurewei Technologies Inc.
Santa Clara, CA
United States of America
Email: ludwig@clemm.org, alexander.clemm@huawei.com
 
Jan Medved
Cisco
Email: jmedved@cisco.com
 
Robert Varga
Pantheon Technologies SRO
Email: robert.varga@pantheon.tech
 
Xufeng Liu
Jabil
Email: xufeng.liu.ietf@gmail.com
 
Hariharan Ananthakrishnan
Packet Design
Email: hari@packetdesign.com
 
Nitin Bahadur
Bracket Computing
Email: nitin_bahadur@yahoo.com

Перевод на русский язык

Николай Малых

nmalykh@protokols.ru

1Internet Engineering Task Force — комиссия по решению инженерных задач Internet.

2Internet Engineering Steering Group — комиссия по инженерным разработкам Internet.

3Опубликовано в RFC 8795. Прим. перев.

Рубрика: RFC | Оставить комментарий