RFC 8795 YANG Data Model for Traffic Engineering (TE) Topologies

Internet Engineering Task Force (IETF)                            X. Liu
Request for Comments: 8795                                Volta Networks
Category: Standards Track                                     I. Bryskin
ISSN: 2070-1721                             Futurewei Technologies, Inc.
                                                               V. Beeram
                                                                 T. Saad
                                                        Juniper Networks
                                                                 H. Shah
                                                                   Ciena
                                                     O. Gonzalez de Dios
                                                              Telefonica
                                                             August 2020

YANG Data Model for Traffic Engineering (TE) Topologies

Модель данных YANG для топологии TE

PDF

Аннотация

Этот документ задаёт модель данных YANG для представления, извлечения и манипуляций с топологией организации трафика (Traffic Engineering или TE). Модель служит основой для зависящих от технологии моделей топологии TE.

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

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

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

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

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

Copyright (c) 2020. Авторские права принадлежат 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. Введение

База данных организации трафика (Traffic Engineering Database или TED) является важным компонентом систем TE на основе MPLS-TE [RFC2702] и GMPLS [RFC3945]. TED — это коллекция сведений TE обо всех узлах и каналах TE в сети. Топология TE схематически показывает узлы и каналы TE данной базы TED. В данной системе TE может существовать одна или несколько топологий TE. С топологией TE работают алгоритмы расчёта путей.

Этот документ задаёт модель данных YANG [RFC7950] для представления, извлечения и манипуляций с топологией TE. Модель включает независимые от технологии блоки топологии TE, которые могут применяться в связанных с технологией топологических моделях TE.

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

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

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

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

TED (Traffic Engineering Database) — база данных организации трафика

Набор сведений TE обо всех узлах и каналах TE в данной сети.

TE topology — топология TE

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

Native TE topology — естественная топология TE

Естественная для данного провайдера топология сети, которая может быть раскрыта через протоколы маршрутизации и/или методы подписки и публикации. На основе этой топологии работают алгоритмы расчёта путей TE.

Customized TE topology — настраиваемая топология TE

Топология, создаваемая провайдером для данного клиента. Такая топология обычно представляет собой абстракции на основе естественной топологии TE у провайдера и представляется клиенту, который при получении сливает её со своей естественной топологией. Алгоритмы расчёта путей у клиента обычно не работают с настраиваемой топологией, а используют результат слияния с естечтвенной топологией клиента.

1.2. Структура дерева

Упрощённое графическое представление модели данных приведено в Приложении A с использованием формата, заданного в [RFC8340] для моделей данных YANG.

1.3. Префиксы имён в модели данных

В этом документе для имён узлов и других объектов модели данных применяются стандартные префиксы, связанные с импортируемыми модулями YANG, как показано в таблице 1.

Таблица . Префиксы модулей YANG.

 

Префикс

Модуль YANG

Документ

yang

ietf-yang-types

[RFC6991]

inet

ietf-inet-types

[RFC6991]

nw

ietf-network

[RFC8345]

nt

ietf-network-topology

[RFC8345]

te-types

ietf-te-types

[RFC8776]

 

2. Классификация топологии TE

Заданная в этом документе модель данных учитывает перечисленные ниже характеристики топологии TE.

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

  • Топология TE не зависит от протокола. Сведения об элементах топологии можно получить от протоколов, основанных на состояниях каналов, но топология может существовать независимо от какого-либо конкретного протокола.

  • Топология TE может не совпадать с топологией маршрутизации в данной системе TE. Топология маршрутизации строится на основе смежности маршрутизаторов. Нет взаимно-однозначного соответствия между каналами TE и смежностью маршрутизаторов. Например, наличие канала TE между парой узлов не обязательно предполагает маршрутную смежность между этими узлами. Дополнительные сведения по этим вопросам представлены в работах [TEAS-TOPO] и [YANG-L3].

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

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

  • Топология TE может быть настраиваемой. Топологии TE данной сети, представляемые провайдером своим клиентам могут настраиваться для каждого клиента. Такая настройка может выполняться провайдером и/или соглашением между провайдером и клиентом. Связь между настроенной топологией и естественной топологией провайдера может быть представлена как иерархия (базовая — наложенная), а в остальном эти две топологии развязаны между собой. Настраиваемая топология предоставляется клиенту, а естественная топология провайдера известна только ему.

3. Абстракции и преобразования при моделировании

3.1. Топология TE

Топология TE — это представление организации трафика с одним или несколькими уровнями топологии сети. Топология TE включает узлы TE (вершины графа), соединённые каналами TE (ребра графа). Топология отображается в граф TE.

3.2. Узел TE

                             | +---+          __
                             | |   | Узел TE  \/ TTP  o LTP
                             | +---+
                             |
                             | ----- Канал TE
                             | ***** Матрица связности узлов,
                             |       Связность локальных каналов TTP
                             | @@@@@ Туннель TE
                             o----------------------------------

   Node-1                                            Node-3
+------------+                                    +------------+
|    TTP-1   |                                    |    TTP-1   |
|LTP  __     |           TE-Tunnel-1              |     __     |
|-6   \/@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\/     |
o    *  *    oLTP-1           Node-2         LTP-6o    *  *    o
|   *    *   |           +------------+           |   *    *   |
|  * TTP-2*  |           |            |           |  * TTP-2*  |
| *   __   * |LTP-2 LTP-6|            |LTP-1 LTP-5| *   __   * |
o*    \/    *o-----------o************o-----------o*    \/    *o
|LTP *  *    | Link-12   |          * | Link-23   |    *  *    |
|-5 *    *   |      LTP-5|        *   |LTP-2      |   *    *   |
+--o------o--+           o************o           +--o------o--+
 LTP-4  LTP-3            | *   *    * |            LTP-4  LTP-3
                         |  **     *  |
                         +--o------o--+
                          LTP-4  LTP-3

LTP: Link Termination Point - точка завершения канала
TTP: Tunnel Termination Point - точка завершения туннеля

Рисунок . Абстракции моделирования топологии TE.


Узел TE — это элемент топологии TE, представляемый вершиной (vertex) графа TE и соответствующий одному или нескольким узлам или части узла (это может быть коммутатор или маршрутизатор, физический или виртуальный). Узел TE принадлехит одной топологии TE и полностью определён в ней. Узлу присваивается уникальный идентификатор в рамках топологии TE. Атрибуты узла TE включают сведения, относящиеся к плоскости данных соответствующего узла или узлов (например, матрица связности), а также данные конфигурации (такие, как имя узла TE). Данный узел TE доступен на графе TE через один или несколько каналов TE, завершающихся узлом TE.

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

На рисунке 1 узлы Node-1, Node-2, Node-3 являются узлами TE.

3.3. Канал TE

Канал TE — это элемент топологии TE, представляемый ребром графа TE. Стрелки на ребре указывают направления (одно или оба) канала TE. При наличии пары параллельных односторнних и разнонаправленных каналов используется ребро без стрелок. Канал TE представляет один или несколько (физических) каналов или часть канала. Канал TE относится к одной топологии TE и полностью определяется ею. Каналу TE назначается уникальный в рамках топологии TE идентификатор. Атрибуты канала TE включают параметры, относящиеся к аспектам плоскости данных соответствующих каналов (невыделенная пропускная способность, карты (пулы) ресурсов и т. п.), а также данные конфигурации (идентификаторы удалённых узлов, идентификаторы каналов, SRLG3, административная раскраска и т. п.). Канал TE присоединяется к узлу TE, заврешающему канал TE через одну точку (Link Termination Point или LTP).

На рисунке 1 каналы TE обозначены Link-12 и Link-23.

3.4. Переходный канал TE для многоуровневых топологий

Сети обычно состоят из нескольких уровней и один или несколько сигналов сети клиентского уровня могут мультиплексироваться и инкапсулироваться в сигнал серверного уровня [RFC5212] [G.805]. Этот сигнал может передаваться в сети уровня серверов через множество узлов, пока сигнал не будет завершён и сигналы уровня клиентов снова не появятся на завершающем серверный уровень узле. Примеры многоуровневых сетей включают (1) IP через MPLS в сети Ethernet и (2) низкоуровневые оптические сигналы (Optical Data Unit-k или ODUk), мультиплексируемые в высокоуровневый сигнал ODUl (l>k), передаваемый через сигнал оптического канала (Optical Channel иои OCh) в оптической транспортной сети (Optical Transport Network или OTN), как указано в [G.872] и [G.709].

Определённые в параграфе 3.3 каналы TE могут служить для представления каналов внутри сетевого уровня. В случае многоуровневой сети узлы и каналы TE позволяют лишь представлять каждый уровень сети как отдельную топологию TE. Каждая из таких одноуровневых топологий TE может быть изолирована от от топологии TE клиентского и среверного уровня (при их наличии). Верхний и нижний уровни сетевой иерархии имеют лишь одну точку смежности с соседним уровнем (выше или ниже). Мультиплексирование сигналов клиентского уровня и их инкапсуляция в сигнал уровня серверов требует обеспечиваемой внутри узла функции (обычно реализованной аппаратно), которую называют межуровневым переходом (layer transition).

                             |                 |
                             | +---+          ---
                             | |   | Узел TE  \ / Переходный
                             | +---+           |  канал
                             |
                             | ----- Канал клиентского уровня
                             | ===== Канал серверного уровня
                             | ***** Граница между уровнями
                             o----------------------------------

   +-------------------+
   | +-------+         |                          +-------+
-----|Коммут.|------+  |             Каналы  -----|Узел   |
   | |клиент.|---+  |  |             клиентского  |клиент.|
-----|уровня |-+ |  |  |             уровня  -----|уровня |
   | +------ + | |  |  |                          +-------+
   |           | |  |  | Клиентский                | |  |
   |           | | ---_| уровень                   --- ---
***|***********|*| \ /*|***************************\ /*\ /****
   |           ---  |  | Серверный      Переходные  |   |
   |Завершение \ /  |  | уровень            каналы  |   |
   |  уровня    |   |  |                            |   |
   |            |   |  |                            |   |
   |         +-------+ |                          +-------+
=============|Коммут.|=====           Каналы  ====|Узел   |====
   |         |сервер.| |              серверного  |сервер.|
=============|уровня |=====           уровня  ====|уровня |====
   |         +-------+ |                          +-------+
   +-------------------+

Представление физического узла        Представление топологии TE

Рисунок . Моделирование многоуровневого узла (в примере 2 уровня).


Одним из основных требований в расчёту пути является возможность нахождения пути между парой конечных точек через многоуровневую сеть, на основе представляющее её топологии TE. Это требует дополнительной конструкции TE, представляющей вожможные переходы между уровнями в многоуровневой топологии TE, для соединения топологий TE отдельных уровней сети. Такой конструкцией является переходный канал TE, представляющий функцию межуровневого перехода внутри узла, который разбирается (декомпозиция) на несколько логических узлов, представленных как узлы TE (см. определения переходного канала для OTN в [G.8080]). link for the OTN). Следовательно, переходный канал TE соединяет узел клиентского уровня с узлом серверного уровня. Канал TE, как указано в параграфе 3.3 имеет LTP одного типа на каждом конце соединения, а пареходный канал TE имеет LTP клиентского уровня на стороне клиента и одну точку LTP серверного уровня на стороне сервера. Следует отметить, что переходные каналы являются вспомогательной функцией в многоуровневой топологии TE и существуют лишь до начала использования, поскольку они представляют потенциальную связность. После установки трассы на уровне сервером между LTP двух переходных каналов, полученный в результате канал клиентского уровня в плоскости данных можно представить как обычный канал TE в топологии клиентского уровня. Переходные каналы TE появляются снова при разрыве трассы на уровне серверов.

3.5. Точка завершения канала TE (LTP)

Точка завершения канала TE (Link Termination Point — или LTP) — это концептуальная точка присоединения узла TE к обному из каналов TE, завершаемому на узле TE. Мощность (cardinality) соединения LTP и связанного канала TE составляет 1:0..1.

На рисунке 1 узел Node-2 имеет шесть LTP — LTP-1 — LTP-6.

3.6. Точка завершения туннеля TE (TTP)

Точка завершения туннеля TE (Tunnel Termination Point или TTP) — это элемент топологии TE, представляющий одну или несколько возможных точек завершения транспортного сервиса (точек адаптации услуги клиентом, таких как транспондер WDM4/OCh). TTP связывается с одним узлом TE (размещается на узле), в области действия которого TTP назначается уникальный идентификатор. В зависимости от внутренних ограничений узла TE доступ к данной точке TTP может осуществляться через один, несколько или все каналы TE, завршающиеся на этом узле TE.

На рисунке 1 узел Node-1 имеет две точки TTP — TTP-1 и TTP-2.

3.7. Матрица связности узла TE

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

На рисунке 1 матрица связности Node-2 имеет вид {<LTP-6, LTP-1>, <LTP-5, LTP-2>, <LTP-5, LTP-4>, <LTP-4, LTP-1>, <LTP-3, LTP-2>}.

3.8. Список локальных соединений TTP (LLCL)

Список локальных соединений TTP (Local Link Connectivity List или LLCL) — это список каналов TE, завершаемых на узле TE, содержащем TTP, с которыми точка TTP может быть соединена. С точки зрения потенциального соединения пути TE список LLCL содержит действительные каналы TE, на который путь TE должен начинаться или заканчиваться для успешного завершения TTP.

На рисунке 1 список LLCL узла Node-1 имеет вид {<TTP-1, LTP-5>, <TTP-1, LTP-2>, <TTP-2, LTP-3>, <TTP-2, LTP-4>}.

3.9. Путь TE

Путь TE — это упорядоченный список каналов и узлов TE в графе топологии TE. Этот путь соединяет пару TTP для использования потенциальным соединением. Например, путь TE может быть результатом успешного расчёта пути для данного транспортно сервиса.

На рисунке 1 путь TE для TE-Tunnel-1 имеет вид {Node-1:TTP-1, Link-12, Node-2, Link-23, Node-3:TTP-1}.

3.10. Блокировка между уровнями TE

Блокировка между уровнями TE — это концепция моделирования, описывающая адаптационные взаимосвязи между уровнями клиентов и сервером, что важно для многоуровневой организации трафика. Это объединение M клиентских LTP и N серверных TTP, в котором данные, приходящие на любую з клиентских точек LTP, могут быть направлены в любую из серверных точек TTP. Межуровневая блокировка TE указывается идентификатором, который уникален среди всех топологий TE, предоставляемых одним провайдером. Идентификатор служит для аннотирования LTP клиентского уровня и TTP серверного уровня, связанных с данной межуровневой блокировкой TE.

                   | +---+          __
                   | |   | Узел TE  \/ TTP  o LTP
                   | +---+
                   |
                   | ----- Канал TE
                   | ***** Локальная связность TTP
                   o----------------------------------

(IL-1) C-LTP-1 +------------+   C-LTP-2 (IL-1)
       --------O   (IL-1)   O--------
(IL-1) C-LTP-3 |   S-TTP-1  |   C-LTP-4 (IL-1)
       --------O     __     0--------
(IL-1) C-LTP-5 |    *\/*    |   C-LTP-6 (IL-1)
       --------O   *    *   O--------
               |  *(IL-1)*  |
       S-LTP-3 | * S-TTP-2* |   S-LTP-4
       --------o*    __    *o--------
               |    *\/*    |
               |   *    *   |
               +--o------o--+
       S-LTP-1 |      | S-LTP-2

Рисунок . Ассоциации идентификатора межуровневой блокировки TE.


На рисунке 3 межуровневая блокировка TE с идентификатором IL-1 связывает 6 LTP клиентского уровня (C-LTP-1 — C-LTP-6) с двумя TTP серверного уровня (S-TTP-1 и S-TTP-2). Они имеют общий атрибут — идентификатор межуровневой блокировки IL-1, который является единственным индикатором связи. В данном случае LTP может (не обязательно) иметь один или несколько идентификаторов межуровневых блокировок. Наличие нескольких идентификаторов означает, что приходящие на LTP данные могут направляться в любую из точек TTP, связанных с этими межуровневыми блокировками. Например, C-LTP-1 может иметь два идентификатора (IL-1 и IL-2). Это будет означать, что C-LTP-1 может использовать для адаптации не только TTP, связанные с блокировкой IL-1 (S-TTP-1 и S-TTP-2), но и любые TTP, связанные с блокировкой IL-2. Точка TTP тоже может иметь один или несколько идентификаторов блокировки, означающих, что она может предложить нескольку услуг адаптации для LTP клиентского уровня, чьи идентификаторы межуровневой блокировки совпадают с её идентификатором. У каждой точки TTP имеется атрибут незарезервированной пропускной способности, указывающий оставшиеся ресурсы адаптации для всех потенциальных LTP клиентского уровня.

LTP и TTP, связанные с одной межуровневой блокировкой, могут размещаться на одном (гибридом, многоуровневом) или разных узлах TE, находящихся в одной или разных топологиях TE. Второй случай особенно важен, поскольку топологии TE разных уровней сети могут моделироваться с использованием разных дополнений к базовой (общей для всех уровней) модели топологии TE.

3.11. Базовая топология TE

Базовой топологией TE считается топология TE, служащая основой для создания наложенных топологий TE.

3.12. Наложенная топология TE

Наложенной топологией TE счиается топология TE, созданная на основе одной или нескольких базовых топологий TE. Каждый узел наложенной топологии TE представляет сегмент базовой топологии TE, каждый канал TE — путь TE в одной из базовых топологий TE. Наложенная и базовые топологии TE могут представлять разные уровни сети (например, OTN/ODUk и WDM/OCh) или размещаться на одном уровне.

3.13. Абстрактная топология TE

Абстрактной топологией TE является топология, содержащая абстрактные элементы (узлы, каналы, TTP). Абстрактная топология TE — это наложенная топология TE, созданная поставщиком топологии и настроенная им для своего клиента на основе одной или нескольких естественных топологий TE (базовые топологии TE), правил провайдера и предпочтений клиента. Например, провайдер топологии первого уровня (такой как контроллер домена) может создать абстрактную топологию TE для своего клиента (такого как многодоменный координатор услуг) на основе одной или нескольких естественных топологий TE у провайдера, локальных правил и профилей, запросов клиента для настройки топологии TE. Пример абстрактной топологии TE приведён на рисунке 4.

                           | +---+
                           | |   | Узел TE
                           | +---+
                           | ----- Канал TE
                           o----------------------------------

+---+              +---+
|S3 |              |S5 |
+---+\           / +---+
      \         /
       \       /
        \+---+/                +---+
        /|AN1|\----------------|S8 |
       / +---+ \               +---+
+---+ /         \ +---+
|S9 |             |S11|
+---+             +---+
      Абстрактная топология TE

       +---+                    +---+
       |S1 |--------------------|S2 |
       +---+                    +---+
        /                          \
       /                            \
+---+ /                  +---+       \ +---+
|S3 |--------------------|S4 |---------|S5 |
+---+\                   +---+         +---+
      \                      \             \
       \                      \             \
        \+---+                 +---+         +---+
        /|S6 |\                |S7 |---------|S8 |
       / +---+ \               +---+\       /+---+
+---+ /         \ +---+              +---+ /
|S9 |-------------|S10|--------------|S11|/
+---+             +---+              +---+
      Естественная топология TE

Рисунок . Абстрактная топология TE.


4. Применимость модели

4.1. Естественная топология TE

Рассматриваемая в этом документе модель подходит для представления и извлечения естественных топологий TE данной системы TE. Рассмотрим топологию сети, представленную на рисунке 5, где узлы R1 .. R9 представляют маршрутизаторы. Пеализация может создать топологию Native TE, используя все узлы и каналы, представленные в данной базе TED, как показано на рисунке 6. Заданную в этом документе модель данных можно использовать для представления и извлечения этой топологии TE.


                           | +---+
                           | |   | Узел TE
                           | +---+
                           | ----- Канал TE
                           o----------------------------------

+---+       +---+        +---+         +---+         +---+
| R1|-------| R2|--------| R3|---------| R4|---------| R5|
+---+       +---+        +---+         +---+         +---+
  |                      /   \         /   \         /
  |                     /     \       /     \       /
  |                    /       \     /       \     /
  |                   /         \   /         \   /
  |                  /           \ /           \ /
+---+             +---+         +---+         +---+
| R6|-------------| R7|         | R8|---------| R9|
+---+             +---+         +---+         +---+

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

    ---------------
    | Естественная|                   |  [ ] Узел TE
    | топология TE|                   |  +++ Канал TE
    ---------------                   o--------------

[R1] ++++ [R2] ++++ [R3] ++++ [R4] ++++ [R5]
  +                +    +    +    +    +
  +               +      +  +      +  +
  +              +        ++        ++
[R6] +++++++++ [R7]      [R8] ++++ [R9]

Рисунок . Естественная топология TE с точки зрения узла R3.


Рассмотрим случай расщепления топологии, когда одни узлы используют OSPF-TE, другие ISIS-TE (рисунок 7). Реализация может создать отдельные топологии TE на основе источника информации. Естественные топологии TE, построенные с использованием лишь узлов и связей, узнанных из конкретного источника, показаны на рисунке 8. Заданную в этом документе модель данных можно использовать для представления и извлечения таких топологий TE.


                           :
Сведения TE от ISIS-TE     : Сведения TE от OSPF-TE
                           :
+---+       +---+        +---+         +---+         +---+
| R1|-------| R2|--------| R3|---------| R4|---------| R5|
+---+       +---+        +---+         +---+         +---+
  |                      / : \         /   \         /
  |                     /  :  \       /     \       /
  |                    /   :   \     /       \     /
  |                   /    :    \   /         \   /
  |                  /     :     \ /           \ /
+---+             +---+    :    +---+         +---+
| R6|-------------| R7|    :    | R8|---------| R9|
+---+             +---+    :    +---+         +---+
                           :

Рисунок . Пример расщепления топологии сети.

-----------------------   :  -----------------------
|Естеств. топология TE|   :  |Естеств. топология TE|
|источник: ISIS-TE    |   :  |источник: OSPF-TE    |
-----------------------   :  -----------------------
                          :
 [R1] ++++ [R2] ++++ [R3] : [R3'] ++++ [R4] ++++ [R5]
  +                +      :      +    +    +    +
  +               +       :       +  +      +  +
  +              +        :        ++        ++
 [R6] +++++++++ [R7]      :       [R8] ++++ [R9]

Рисунок . Естественные топологии TE с точки зрения узла R3.


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

4.2. Настраиваемая топология TE

Настраиваемая топология TE — это топология, измененная провайдером в соответствии с потребностями и предпочтениями отдельного клиента. Представленная в этом документе модель подходит для создания, изменения и извлечения топологий Customized TE. Модель позволяет провайдеру представить сеть для клиента абстрактными элементами TE. These customized topologies contain sufficient information for the client to compute and select paths according to its policies.

Рассмотрим топологию сети, представленную на рисунке 9. Это типичная оптическая транспортная сеть для пакетов, где домен уровня WDM служит серверным доменом для обеспечения транспортной связности домена пакетного уровня (домен клиентов). Узлы R1, R2, R3, R4 являются маршрутизаторами IP, соединёнными через оптическую транспортну. Сеть WDM. A, B, C, D, E, F — узлы WDM, образующие домен серверной сети.

                             | +---+            /-\
                             | |   | Узел      (   ) Узел
                             | +---+ маршрутиз. \-/  WDM
                             |
                             o----------------------------

+---+        /-\          /-\           /-\          +---+
| R1|-------( A )--------( C )---------( E )---------| R3|
+---+        \-/          \-/           \-/          +---+
                         /   \         /   \
                        /     \       /     \
                       /       \     /       \
                      /         \   /         \
                     /           \ /           \
    +---+          /-\           /-\           /-\          +---+
    | R2|---------( B )---------( D )---------( F )---------| R4|
    +---+          \-/           \-/           \-/          +---+

Рисунок .Пример пакетной оптической топологии.


Цель состоит в дополнении клиентской топологии TE топологией Customized TE, полученной из сети WDM. С учётом доступности путей A-E, B-F, B-E (рисунок 10) клиенту представляется топология Customized TE, показанная на рисунке 11. Эта топология сливается с клиентской топологией Native TE, создавая в топологию, показанную на рисунке 12.


                                       | ***** путь WDM B-F 
                                       | @@@@@ путь WDM B-E
                                       | $$$$$ путь WDM A-E 
                                       o--------------------

+---+        /-\ $$$$$$$$ /-\ $$$$$$$$$ /-\          +---+
| R1|-------( A )--------( C )---------( E )---------| R3|
+---+        \-/         @\-/ @@@@@@@@@ \-/          +---+
                        @/   \         /   \
                       @/     \       /     \
                      @/       \     /       \
                     @/         \   /         \
                    @/           \ /           \
    +---+          /-\ ********* /-\ ********* /-\          +---+
    | R2|---------( B )---------( D )---------( F )---------| R4|
    +---+          \-/           \-/           \-/          +---+

Рисунок .Пути в домене провайдера.


++++++++ [A] ++++++++++++++++++++ [E] +++++++++
                             +++++
                         ++++
                     ++++
                 ++++
             ++++
++++++++ [B] ++++++++++++++++++++ [F] +++++++++

Рисунок .Настраиваемая топология TE для клиента.

[R1] ++++++++ [A] ++++++++++++++++++++ [E] +++++++++ [R3]
                                  +++++
                              ++++
                          ++++
                      ++++
                  ++++
[R2] ++++++++ [B] ++++++++++++++++++++ [F] +++++++++ [R4]

Рисунок .Слияние настроенной топологии TE с естественной топологией клиента.


Описанная в локументе модель данных позволяет представлять, извлекать и манипулировать топологией Customized TE, показанной на рисунке 11.

Настраиваемая топология TE не обязательно является абстрактной топологией TE. Провайдер может создать, например, абстрактную топологию TE того или иного типа (один абстрактный узел с матрицей связности, граничные узлы, соединённые через многосвязную топологию абстрактных каналов) и раскрыть её некоторым или всем клиентам, предполагая, что те будут использовать её без настройки. С другой стороны, клиент может запросить настроенный вариант провайдерской топологии Native TE (например, попросив удалить каналы TE, принадлежащие определенным уровням, слишком медленные, незащищённые или имеющие определённую близость). Результирующая топология TE не будет абстрактной (нет абстрактных элементов), но будет настроенной (изменённой по запросу клиента).

Поле идентификатора клиента в идентификаторе топологии (параграф 5.4) указывает, для какого клиента настроена топология. Хотя уполномоченный клиент может получить топологию TE с идентификатором другого клиента, он сможет использовать лишь топологии TE со своим идентификатором или значением 0. Если клиент начинает реконфигурацию топологии, его идентификатор будет автоматически помещаться в в поле идентификатора топологии для всех будущих настроек и обновлений данной топологии.

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

Хотя эта модель данных разрешает разным клиентам доступ к сведениям топологии TE, реализация может ограничивать такой доступ, предоставляя некоторые поля лишь определенным клиентам. Механизм такого ограничения предоставляет модель контроля доступа к конфигурации сети (Network Configuration Access Control Model или NACM) [RFC8341].

4.3. Слияние топологий TE от нескольких провайдеров

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

  • идентификацию соседних доменов и соединение их топологий по горизонтали путём соединения с их междоменными каналами TE с открытым концом;

  • замена идентификаторов узлов и каналов TE, а также SRLG идентификаторами из отдельного пространства имён (это требуется по причине того, что технологии TE считаются независимыми и возможны конфликты между указанными идентификаторами);

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

На рисунке 13 представлен пример слияния клиентом топологий TE, полученных от провайдеров.

/---\      +---+    +---+      +---+    +---+      /---\
|C11|------|S13|----|S15|------|S23|----|S25|------|C21|
\---/      +---+\   +---+      +---+   /+---+      \---/
                 \                    /
                  \                  /
                   \+---+      +---+/   +---+      /---\
                    |S18|------|S24|    |S28|------|C22|
                    +---+      +---+\  /+---+      \---/
                                     \/
                                     /\
/---\      +---+    +---+      +---+/  \+---+      /---\
|C12|------|S19|----|S17|------|S29|----|S27|------|C23|
\---/      +---+    +---+      +---+    +---+      \---/

   Топология TE домена 1            Топология TE домена 2

        +---+    +---+                  +---+    +---+
   -----|S13|----|S15|----          ----|S23|----|S25|----
        +---+\   +---+                  +---+   /+---+
              \                                /
               \                              /
                \+---+                  +---+/   +---+
                 |S18|----          ----|S24|    |S28|----
                 +---+                  +---+\  /+---+
                                              \/
                                              /\
        +---+    +---+                  +---+/  \+---+
   -----|S19|----|S17|----          ----|S29|----|S27|----
        +---+    +---+                  +---+    +---+

Рисунок . Пример слияния топологий доменов TE.


На рисунке 13 каждый из двух провайдеров предосталяет клиенту топологию TE (абстрактную или истественную), описывающую контролируемый провайдером домен сети. Клиент, сверяясь с атрибутами междоменных каналов TE, такими как идентификаторы стыков между доменами или идентификаторы удалённых узлов/каналов TE (как указано в топологии TE), способен определить, что:

  1. домены являются смежными и соединены междоменными каналами TE;

  2. каждый домен подключён к отдельному сайту клиента, домен слева на рисунке соединён с клиентскими устройствами C11 и C12, домен справа — с C21, C22, C23.

Клиент соединяет каналы TE с открытым концом, как показано в верхней части рисунка.

Как уже упоминалось, одним из способов соединения междоменных каналов TE с открытым концом из разных доменов является обязательное указание провайдерами отрибута удалённого узла/канала в предоставляемых междоменных каналах TE. Однако это может оказаться недостаточно гибким, например, провайдеры могут не значть соответствующих идентификаторов удалённых узлов/каналов. Ещё важнее то, что этот вариант не позволяет клиенту смешивать и сопоставлять несколько топологий (более 1) от одного провайдера (см. параграф 4.4). Более гибким вариантом соединения междоменных каналов TE с открытым концом является их аннотирование атрибутом идентификатора междоменного стыка, который уникален в масштабе сети и указывает в сети соединение, поддерживающее данный междоменный канал TE. Вместо указания идентификатора удалённого узла/канала междоменный канал TE может предоставлять ненулевой идентификатор междоменного стыка (plug). Предполагается, что топологии TE двух соседних доменов (от разных провайдеров) будут иметь хотя ба по одному междоменному каналу TE с открытым концом, имеющему идентификатор медоменного стыка, соответствующий идентификатору, предоставленному соседом. Например, междоменный канал TE, начинающийся на узле S15 топологии TE домена 1 (рисунок 13), и междоменный канал TE, начинающийся на узле S23 топологии TE домена 2, могут указывать совпадающие идентификаторы веждоменных стыков ID (например, 175344). Это позволяет клиенту идентифицировать смежные узлы в раздельных соседних топологиях TE и распознавать соединяющие их междоменные каналы TE, независимо от соответствующих идетификаторов каналов/узлов (которые, как было отмечено выше, могут выделяться из независимых пространств). Идентификаторы междоменных стыков могут назначаться и поддерживаться центральным органом сети, а также автоматически обнаруживаться в динамическом режиме, например, по протоколу управления каналами (Link Management Protocol или LMP).

Кроме того, клиент переименовывает узлы и каналы TE, а также группы SRLG, представленные в абстрактных топологиях, назначая им идентификаторы, выделенные из поддерживаемого клиентом пространства имён. Такое переименование требуется потому, что две абстрактные топологии TE могут иметь свои пространства имён, которые в общем случае независимы одно от другого, поэтому идентификаторы могут конфликтовать между собой. Например, в обеих топологиях TE могут быть узлы TE с именем S7, которые после переименования получат в слитой топологии TE имена S17 и S27.

По завершении процесса слияния клиент может использовать полученную в результате топологию TE для расчёта путей через оба домена, например, пути TE от C11 к C23.

4.4. Несколько абстрактных топологий TE от одного провайдера

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

Абстрактная топология TE 1 домена 1  Абстрактная топология TE 1 домена 2

     +---+    +---+                      +---+    +---+
-----|S13|----|S15|----              ----|S23|----|S25|----
     +---+\   +---+                      +---+   /+---+
           \                                    /
            \                                  /
             \+---+                      +---+/   +---+
              |S18|----              ----|S24|    |S28|----
              +---+                      +---+\  /+---+
                                               \/
                                               /\
     +---+    +---+                      +---+/  \+---+
-----|S19|----|S17|----              ----|S29|----|S27|----
     +---+    +---+                      +---+    +---+

Абстрактная топология TE 2 домена 1  Абстрактная топология TE 2 домена 2

     +------------+                      +------------+
-----|            |----              ----|            |----
     |            |                      |            |
     |    AN1     |----              ----|    AN1     |----
     |            |                      |            |
-----|            |----              ----|            |----
     +------------+                      +------------+

Рисунок . Пример слияния топологий доменов TE.


Клиенту следует самостоятельно (на основе локальной конфигурации и правил, переданных клиенту его клиентами) определять, как смешивать и сопоставлять топологии TE, предоставленные провайдерами, а также как сливать их в свои естественные топологии TE. Клиент также определяет число слитых топологий TE, которые ему нужно создать и поддерживать. Например, в дополнение к слитой топологии TE, показанной в врехней части рисунка 13, клиент может слить абстрактные топологии TE, полученные от двух провайдеров (см. рисунок 14), в свои дополнительные топологии Native TE, как показано на рисунке 15.

           Слитая клиентом топология TE 2

/---\      +------------+      +------------+      /---\
|C11|------|            |------|            |------|C21|
\---/      |            |      |            |      \---/
           |            |      |            |
           |            |      |            |
           |            |      |            |      /---\
           |    AN11    |------|    AN21    |------|C22|
           |            |      |            |      \---/
           |            |      |            |
           |            |      |            |
/---\      |            |      |            |      /---\
|C12|------|            |------|            |------|C23|
\---/      +------------+      +------------+      \---/

           Слитая клиентом топология TE 3

/---\      +------------+      +---+    +---+      /---\
|C11|------|            |------|S23|----|S25|------|C21|
\---/      |            |      +---+   /+---+      \---/
           |            |             /
           |            |            /
           |            |      +---+/   +---+      /---\
           |    AN11    |------|S24|    |S28|------|C22|
           |            |      +---+\  /+---+      \---/
           |            |            \/
           |            |            /\
/---\      |            |      +---+/  \+---+      /---\
|C12|------|            |------|S29|----|S27|------|C23|
\---/      +------------+      +---+    +---+      \---/

Рисунок . Несколько естественных (слитых) клиентских топологий TE.


Отметим, что разрешение клиенту смешивать и сопоставлять несколько топологий TE предполагает использование идентификаторов междоменных стыков (а не удалённых узлов/каналов) для идентификации соседних доменов и распознавания междоменного канала.

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

5. Вопросы моделирования

5.1. Элементы топологии сети

Блоки построения топологии сети рассмотрены в [RFC8345]. Заданная в этом документе модель топологии TE использует и дополняет модуль ietf-network-topology, заданный в [RFC8345].

+------------------------+
| Модель топологии сети  |
| (ietf-network-topology)|
+------------------------+
             |
             |
             V
+------------------------+
|         Модель         |
|      топологии TE      |
+------------------------+

Рисунок . Дополнение модели топологии сети.


5.2. Независимая от технологии модель топологии TE

Заданная в этом документе модель топологии TE не зависит от сетевой технологии и модели для конкретных технологий могут дополнять её, как показано на рисунке 17.

             +-----------------------------+
             |      Модель топологии TE    |
             +-----------------------------+
                            |
       +-------------+-------------+-------------+
       |             |             |             |
       V             V             V             V
+----------------+                        +----------------+
| Зависящая от   |                        | Зависящая от   | 
| технологии     | ...................... | технологии     |
| модель         |                        | модель         |
| топологии TE 1 |                        | топологии TE n |
+----------------+                        +----------------+

Рисунок . Дополнение независимой от технологии модели топологии TE.


5.3. Структура модели

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

   module: ietf-te-topology
     augment /nw:networks/nw:network/nw:network-types:
       +--rw te-topology!

     augment /nw:networks:
       +--rw te!
          +--rw templates
             +--rw node-template* [name] {template}?
             |  ............
             +--rw link-template* [name] {template}?
                ............

     augment /nw:networks/nw:network:
       +--rw te-topology-identifier
       |  +--rw provider-id?   te-global-id
       |  +--rw client-id?     te-global-id
       |  +--rw topology-id?   te-topology-id
       +--rw te!
          |  ............

     augment /nw:networks/nw:network/nw:node:
       +--rw te-node-id?   te-types:te-node-id
       +--rw te!
          |  ............
          +--rw tunnel-termination-point* [tunnel-tp-id]
             +--rw tunnel-tp-id    binary
             |  ............
             +--rw supporting-tunnel-termination-point*
                     [node-ref tunnel-tp-ref]
                |  ............

     augment /nw:networks/nw:network/nt:link:
       +--rw te!
          |  ..........

     augment /nw:networks/nw:network/nw:node/nt:termination-point:
       +--rw te-tp-id?   te-types:te-tp-id
       +--rw te!
          |  ............

5.4. Идентификаторы топологии

Топология TE однозначно указывается ключом, состоящим из трёх компонентов — topology-id, provider-id, client-id. Сочетание provider-id и topology-id однозначно указывает топологию Native TE для данного провайдера, client-id применяется лишь вместе с настраиваемыми топологиями TE, а client-id = 0 указывает топологию Native TE.

     augment /nw:networks/nw:network:
       +--rw te-topology-identifier
       |  +--rw provider-id?   te-global-id
       |  +--rw client-id?     te-global-id
       |  +--rw topology-id?   te-topology-id
       +--rw te!
          |  ............

5.5. Базовые атрибуты канала TE

Модель охватывает определения базовых атрибутов канала TE — пропускной способности, административных групп, SRLG, возможностей коммутации, расширений показателей TE и т. п.

     +--rw te-link-attributes
        .....................
        +--rw admin-status?                     te-admin-status
        |  .....................
        +--rw link-index?                       uint64
        +--rw administrative-group?             te-types:admin-groups
        +--rw link-protection-type?             enumeration
        +--rw max-link-bandwidth?               te-bandwidth
        +--rw max-resv-link-bandwidth?          te-bandwidth
        +--rw unreserved-bandwidth* [priority]
        |  .....................
        +--rw te-default-metric?                uint32
        |  .....................
        +--rw te-srlgs
        +--rw te-nsrlgs {nsrlg}?        .....................

5.6. Базовые атрибуты узла TE

Модель охватывает определения базовых атрибутов узла TE. Определение матрицы связности приведено ниже.

     +--rw te-node-attributes
        ...........
        +--rw connectivity-matrices
        ...........
        |  +--rw connectivity-matrix* [id]
        |  |  +--rw id            uint32
        |  |  +--rw from
        |  |  |  +--rw tp-ref?        leafref
        |  |  |  +--rw label-restrictions
        |  |  +--rw to
        |  |  |  +--rw tp-ref?        leafref
        |  |  |  +--rw label-restrictions
        |  |  +--rw is-allowed?   boolean
        ...........
        |  |  +--rw underlay! {te-topology-hierarchy}?
        ...........
        |  |  +--rw path-constraints
        ...........
        |  |  +--rw optimizations
        ...........
        |  |  +--ro path-properties
        ...........

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

     +--rw tunnel-termination-point* [tunnel-tp-id]
        +--rw tunnel-tp-id               binary
        +--rw admin-status?              te-types:te-admin-status
        +--rw name?                      string
        +--rw switching-capability?      identityref
        +--rw encoding?                  identityref
        +--rw inter-layer-lock-id*       uint32
        +--rw protection-type?           identityref
        +--rw client-layer-adaptation
        ...........
        +--rw local-link-connectivities
        ...........
        |  +--rw local-link-connectivity* [link-tp-ref]
        |     +--rw link-tp-ref                leafref
        |     +--rw label-restrictions
        ...........
        |     +--rw is-allowed?                 boolean
        |     +--rw underlay {te-topology-hierarchy}?
        ...........
        |     +--rw path-constraints
        ...........
        |     +--rw optimizations
        ...........
        |     +--ro path-properties
        ...........
        +--rw supporting-tunnel-termination-point*
                [node-ref tunnel-tp-ref]
           +--rw node-ref         inet:uri
           +--rw tunnel-tp-ref    binary

Атрибуты, размещённые непосредственно под контейнером connectivity-matrices, являются принятыми по умолчанию для всех записей матрицы связности, когда соответствующие атрибуты для записей не заданы. При задании таких атрибутов они переопределяют атрибуты, размещённые непосредственно под контейнером connectivity-matrices. Такие же правила применяются к атрибутам, размещённым непосредственно под контейнером local-link-connectivities.

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

5.7. Источники данных TED

Модель позволяет каждому топологическому элементу TE иметь несколько источников сведений TE (OSPF-TE, ISIS-TE, BGP-LS5, пользовательские, системные и др.), с каждым из которых связывает уровень предпочтений доверия, указывающий приоритет. Когда настраиваемая тпология TE сливается в клиентскую топологию Native TE, объединённые элементы топологии указывают как источник сведений соответствующую топологию Customized TE.

     augment /nw:networks/nw:network/nw:node:
       +--rw te!
          ...........
          +--ro information-source?            te-info-source
          +--ro information-source-instance?   string
          +--ro information-source-state
          |  +--ro credibility-preference?    uint16
          |  +--ro logical-network-element?   string
          |  +--ro network-instance?          string
          |  +--ro topology
          |     +--ro node-ref?      leafref
          |     +--ro network-ref?   leafref
          +--ro information-source-entry*
          |       [information-source information-source-instance]
          |  +--ro information-source             te-info-source
          |  +--ro information-source-instance    string
                ............

     augment /nw:networks/nw:network/nt:link:
       +--rw te!
          ...........
          +--ro information-source?            te-info-source
          +--ro information-source-instance?   string
          +--ro information-source-state
          |  +--ro credibility-preference?    uint16
          |  +--ro logical-network-element?   string
          |  +--ro network-instance?          string
          |  +--ro topology
          |     +--ro link-ref?      leafref
          |     +--ro network-ref?   leafref
          +--ro information-source-entry*
          |       [information-source information-source-instance]
          |  +--ro information-source                te-info-source
          |  +--ro information-source-instance       string
                ............

5.8. Базовые и наложенные узлы и каналы

Модель отражает взаимоотношения «базовый-наложенный» для узлов и каналов TE. Например, в сети с иерархией нескольких топологий TE эта модель позволяет пользователю начать с конкретного элемента в топологии верхнего уровня и пройти вниз по иерархии до поддерживающих элементов топологии. Эти взаимоотношения указываются в поле underlay-topology для узла и через поле underlay для канала. Использовать эти поля не обязательно и эта функциональность помечена как feature (te-topology-hierarchy).

     augment /nw:networks/nw:network/nw:node:
       +--rw te-node-id?   te-types:te-node-id
       +--rw te!
          +--rw te-node-template*           leafref {template}?
          +--rw te-node-attributes
          |  +--rw admin-status?            te-types:te-admin-status
          |  |  ....................
          |  +--rw underlay-topology {te-topology-hierarchy}?
          |     +--rw network-ref?   leafref

     augment /nw:networks/nw:network/nt:link:
       +--rw te!
          +--rw te-link-attributes
          |  ....................
          |  +--rw underlay {te-topology-hierarchy}?
          |  |  +--rw enabled?                     boolean
          |  |  +--rw primary-path
          |  |  |  +--rw network-ref?    leafref
          |  |  |     ....................
          |  |  +--rw backup-path* [index]
          |  |  |  +--rw index           uint32
          |  |  |  +--rw network-ref?    leafref
          |  |  |     ....................
          |  |  +--rw protection-type?             identityref
          |  |  +--rw tunnel-termination-points
          |  |  |  +--rw source?        binary
          |  |  |  +--rw destination?   binary
          |  |  +--rw tunnels
          |  |  |  ....................

5.9. Шаблоны

Модель данных позволяет пользователю задавать шаблоны и применять их для настройки каналов и узлов. Применение шаблонов не обязательно и они помечены как feature (template).

     augment /nw:networks/nw:network/nw:node:
       +--rw te-node-id?   te-types:te-node-id
       +--rw te!
          +--rw te-node-template*
          |       -> ../../../../te/templates/node-template/name
          |       {template}?

     augment /nw:networks/nw:network/nt:link:
       +--rw te!
          +--rw te-link-template*
          |       -> ../../../../te/templates/link-template/name
          |       {template}?

     augment /nw:networks:
       +--rw te!
          +--rw templates
             +--rw node-template* [name] {template}?
             |  +--rw name
             |  |       te-types:te-template-name
             |  +--rw priority?                  uint16
             |  +--rw reference-change-policy?   enumeration
             |  +--rw te-node-attributes
                ..........
             +--rw link-template* [name] {template}?
                +--rw name
                |       te-types:te-template-name
                +--rw priority?                  uint16
                +--rw reference-change-policy?   enumeration
                +--rw te-link-attributes
                ..........

Для элемента конфигурации можно задать несколько шаблонов. Если два или более шаблона задают значение одного конфигурационного поля, устанавливается значение из шаблона с более высоким приоритетом. Приоритет указывается целым числом от 0 до 65535 и ментшее значение указывает более высокий приоритет. Параметр reference-change-policy задаёт действие, которое нужно выполнить при изменении шаблона для элемента конфигурации, ссылающегося на этот шаблон. Варианты включают отсутствие действий, отклонение изменения шаблона и применение изменения к соответствующей конфигурации.

5.10. Параметры планирования

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

Модель данных YANG для планирования конфигурации, заданная в [YANG-CFG-SCHED], позволяет задать расписание конфигурации без влияния на описываемую здесь модель данных.

5.11. Уведомления

Уведомления являются важными компонентами любой модели данных топологии. В [RFC8639] и [RFC8641] задан механизм подписки и выталкивания сообщений для хранилищ YANG. Этот механизм позволяет пользователю:

  • подписаться на уведомления по клиентам;

  • задать фильтры субдеревьев или XPath6 для указания желаемого содержимого;

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

6. Рекомендации по созданию связанных с технологией дополнений

Заданная в этом документе модель топологии TE не зависит от технологии, поскольку она определяет концепции, абстракции и атрибуты, которые являются общими для разных сетевых технологий. Предполагается широкое применение этой базовой модели для определения связанных с технологией моделей топологии TE на разных уровнях. [YANG-WSON], [YANG-OTN], [YANG-L3] являются примерами зависящих от технологии моделей TE. Создателям таких моделей рекомендуется дополнять контейнеры базовой модели топологии TE, такие как топологии, узлы и каналы TE, точки завершения каналов (LTP) и туннелей (TTP), пропускная способность и метки, связанными с уровнем атрибутами вместо создания новых контейнеров.

Рассмотрим связанную с технологией модель example-topology.

   module: example-topology
     augment /nw:networks/nw:network/nw:network-types/tet:te-topology:
       +--rw example-topology!
     augment /nw:networks/nw:network/tet:te:
       +--rw attributes
          +--rw attribute-1?   uint8
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:te-node-attributes:
       +--rw attributes
          +--rw attribute-2?   uint8
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:te-node-attributes/tet:connectivity-matrices:
       +--rw attributes
          +--rw attribute-3?   uint8
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:te-node-attributes/tet:connectivity-matrices
               /tet:connectivity-matrix:
       +--rw attributes
          +--rw attribute-3?   uint8
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:tunnel-termination-point:
       +--rw attributes
          +--rw attribute-4?   uint8
     augment /nw:networks/nw:network/nw:node/nt:termination-point
               /tet:te:
       +--rw attributes
          +--rw attribute-5?   uint8
     augment /nw:networks/nw:network/nt:link/tet:te
               /tet:te-link-attributes:
       +--rw attributes
          +--rw attribute-6?   uint8

Зависящую от технологии пропускную способность TE в этом примере можно задать с помощью приведённых ниже дополнений (операторы augment).

     augment /nw:networks/tet:te/tet:templates/tet:link-template
               /tet:te-link-attributes
               /tet:interface-switching-capability/tet:max-lsp-bandwidth
               /tet:te-bandwidth/tet:technology:
       +--:(example)
          +--rw example
             +--rw bandwidth-1?   uint32
     augment /nw:networks/tet:te/tet:templates/tet:link-template
               /tet:te-link-attributes/tet:max-link-bandwidth
               /tet:te-bandwidth/tet:technology:
       +--:(example)
          +--rw example
             +--rw bandwidth-1?   uint32
     augment /nw:networks/tet:te/tet:templates/tet:link-template
               /tet:te-link-attributes/tet:max-resv-link-bandwidth
               /tet:te-bandwidth/tet:technology:
       +--:(example)
          +--rw example
             +--rw bandwidth-1?   uint32
     augment /nw:networks/tet:te/tet:templates/tet:link-template
               /tet:te-link-attributes/tet:unreserved-bandwidth
               /tet:te-bandwidth/tet:technology:
       +--:(example)
          +--rw example
             +--rw bandwidth-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:te-node-attributes/tet:connectivity-matrices
               /tet:path-constraints/tet:te-bandwidth/tet:technology:
       +--:(example)
          +--rw example
             +--rw bandwidth-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:te-node-attributes/tet:connectivity-matrices
               /tet:connectivity-matrix/tet:path-constraints
               /tet:te-bandwidth/tet:technology:
       +--:(example)
          +--rw example
             +--rw bandwidth-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:information-source-entry/tet:connectivity-matrices
               /tet:path-constraints/tet:te-bandwidth/tet:technology:
       +--:(example)
          +--ro example
             +--ro bandwidth-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:information-source-entry/tet:connectivity-matrices
               /tet:connectivity-matrix/tet:path-constraints
               /tet:te-bandwidth/tet:technology:
       +--:(example)
          +--ro example
             +--ro bandwidth-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:tunnel-termination-point/tet:client-layer-adaptation
               /tet:switching-capability/tet:te-bandwidth
               /tet:technology:
       +--:(example)
          +--rw example
             +--rw bandwidth-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:tunnel-termination-point
               /tet:local-link-connectivities/tet:path-constraints
               /tet:te-bandwidth/tet:technology:
       +--:(example)
          +--rw example
             +--rw bandwidth-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:tunnel-termination-point
               /tet:local-link-connectivities
               /tet:local-link-connectivity/tet:path-constraints
               /tet:te-bandwidth/tet:technology:
       +--:(example)
          +--rw example
             +--rw bandwidth-1?   uint32
     augment /nw:networks/nw:network/nt:link/tet:te
               /tet:te-link-attributes
               /tet:interface-switching-capability/tet:max-lsp-bandwidth
               /tet:te-bandwidth/tet:technology:
       +--:(example)
          +--rw example
             +--rw bandwidth-1?   uint32
     augment /nw:networks/nw:network/nt:link/tet:te
               /tet:te-link-attributes/tet:max-link-bandwidth
               /tet:te-bandwidth/tet:technology:
       +--:(example)
          +--rw example
             +--rw bandwidth-1?   uint32
     augment /nw:networks/nw:network/nt:link/tet:te
               /tet:te-link-attributes/tet:max-resv-link-bandwidth
               /tet:te-bandwidth/tet:technology:
       +--:(example)
          +--rw example
             +--rw bandwidth-1?   uint32
     augment /nw:networks/nw:network/nt:link/tet:te
               /tet:information-source-entry
               /tet:interface-switching-capability/tet:max-lsp-bandwidth
               /tet:te-bandwidth/tet:technology:
       +--:(example)
          +--ro example
             +--ro bandwidth-1?   uint32
     augment /nw:networks/nw:network/nt:link/tet:te
               /tet:information-source-entry/tet:max-link-bandwidth
               /tet:te-bandwidth/tet:technology:
       +--:(example)
          +--ro example
             +--ro bandwidth-1?   uint32
     augment /nw:networks/nw:network/nt:link/tet:te
               /tet:information-source-entry/tet:max-resv-link-bandwidth
               /tet:te-bandwidth/tet:technology:
       +--:(example)
          +--ro example
             +--ro bandwidth-1?   uint32
     augment /nw:networks/nw:network/nt:link/tet:te
               /tet:information-source-entry/tet:unreserved-bandwidth
               /tet:te-bandwidth/tet:technology:
       +--:(example)
          +--ro example
             +--ro bandwidth-1?   uint32
     augment /nw:networks/nw:network/nw:node/nt:termination-point/tet:te
               /tet:interface-switching-capability/tet:max-lsp-bandwidth
               /tet:te-bandwidth/tet:technology:
       +--:(example)
          +--rw example
             +--rw bandwidth-1?   uint32

Зависящие от технологии метки TE в этом примере можно задать с помощью приведённых ниже дополнений.

     augment /nw:networks/tet:te/tet:templates/tet:link-template
               /tet:te-link-attributes/tet:underlay/tet:primary-path
               /tet:path-element/tet:type/tet:label/tet:label-hop
               /tet:te-label/tet:technology:
       +--:(example)
          +--rw example
             +--rw label-1?   uint32
     augment /nw:networks/tet:te/tet:templates/tet:link-template
               /tet:te-link-attributes/tet:underlay/tet:backup-path
               /tet:path-element/tet:type/tet:label/tet:label-hop
               /tet:te-label/tet:technology:
       +--:(example)
          +--rw example
             +--rw label-1?   uint32
     augment /nw:networks/tet:te/tet:templates/tet:link-template
               /tet:te-link-attributes/tet:label-restrictions
               /tet:label-restriction/tet:label-start/tet:te-label
               /tet:technology:
       +--:(example)
          +--rw example
             +--rw label-1?   uint32
     augment /nw:networks/tet:te/tet:templates/tet:link-template
               /tet:te-link-attributes/tet:label-restrictions
               /tet:label-restriction/tet:label-end/tet:te-label
               /tet:technology:
       +--:(example)
          +--rw example
             +--rw label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:te-node-attributes/tet:connectivity-matrices
               /tet:label-restrictions/tet:label-restriction
               /tet:label-start/tet:te-label/tet:technology:
       +--:(example)
          +--rw example
             +--rw label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:te-node-attributes/tet:connectivity-matrices
               /tet:label-restrictions/tet:label-restriction
               /tet:label-end/tet:te-label/tet:technology:
       +--:(example)
          +--rw example
             +--rw label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:te-node-attributes/tet:connectivity-matrices
               /tet:underlay/tet:primary-path/tet:path-element/tet:type
               /tet:label/tet:label-hop/tet:te-label/tet:technology:
       +--:(example)
          +--rw example
             +--rw label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:te-node-attributes/tet:connectivity-matrices
               /tet:underlay/tet:backup-path/tet:path-element/tet:type
               /tet:label/tet:label-hop/tet:te-label/tet:technology:
       +--:(example)
          +--rw example
             +--rw label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:te-node-attributes/tet:connectivity-matrices
               /tet:path-properties/tet:path-route-objects
               /tet:path-route-object/tet:type/tet:label/tet:label-hop
               /tet:te-label/tet:technology:
       +--:(example)
          +--ro example
             +--ro label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:te-node-attributes/tet:connectivity-matrices
               /tet:connectivity-matrix/tet:from/tet:label-restrictions
               /tet:label-restriction/tet:label-start/tet:te-label
               /tet:technology:
       +--:(example)
          +--rw example
             +--rw label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:te-node-attributes/tet:connectivity-matrices
               /tet:connectivity-matrix/tet:from/tet:label-restrictions
               /tet:label-restriction/tet:label-end/tet:te-label
               /tet:technology:
       +--:(example)
          +--rw example
             +--rw label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:te-node-attributes/tet:connectivity-matrices
               /tet:connectivity-matrix/tet:to/tet:label-restrictions
               /tet:label-restriction/tet:label-start/tet:te-label
               /tet:technology:
       +--:(example)
          +--rw example
             +--rw label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:te-node-attributes/tet:connectivity-matrices
               /tet:connectivity-matrix/tet:to/tet:label-restrictions
               /tet:label-restriction/tet:label-end/tet:te-label
               /tet:technology:
       +--:(example)
          +--rw example
             +--rw label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:te-node-attributes/tet:connectivity-matrices
               /tet:connectivity-matrix/tet:underlay/tet:primary-path
               /tet:path-element/tet:type/tet:label/tet:label-hop
               /tet:te-label/tet:technology:
       +--:(example)
          +--rw example
             +--rw label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:te-node-attributes/tet:connectivity-matrices
               /tet:connectivity-matrix/tet:underlay/tet:backup-path
               /tet:path-element/tet:type/tet:label/tet:label-hop
               /tet:te-label/tet:technology:
       +--:(example)
          +--rw example
             +--rw label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:te-node-attributes/tet:connectivity-matrices
               /tet:connectivity-matrix/tet:path-properties
               /tet:path-route-objects/tet:path-route-object/tet:type
               /tet:label/tet:label-hop/tet:te-label/tet:technology:
       +--:(example)
          +--ro example
             +--ro label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:information-source-entry/tet:connectivity-matrices
               /tet:label-restrictions/tet:label-restriction
               /tet:label-start/tet:te-label/tet:technology:
       +--:(example)
          +--ro example
             +--ro label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:information-source-entry/tet:connectivity-matrices
               /tet:label-restrictions/tet:label-restriction
               /tet:label-end/tet:te-label/tet:technology:
       +--:(example)
          +--ro example
             +--ro label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:information-source-entry/tet:connectivity-matrices
               /tet:underlay/tet:primary-path/tet:path-element/tet:type
               /tet:label/tet:label-hop/tet:te-label/tet:technology:
       +--:(example)
          +--ro example
             +--ro label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:information-source-entry/tet:connectivity-matrices
               /tet:underlay/tet:backup-path/tet:path-element/tet:type
               /tet:label/tet:label-hop/tet:te-label/tet:technology:
       +--:(example)
          +--ro example
             +--ro label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:information-source-entry/tet:connectivity-matrices
               /tet:path-properties/tet:path-route-objects
               /tet:path-route-object/tet:type/tet:label/tet:label-hop
               /tet:te-label/tet:technology:
       +--:(example)
          +--ro example
             +--ro label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:information-source-entry/tet:connectivity-matrices
               /tet:connectivity-matrix/tet:from/tet:label-restrictions
               /tet:label-restriction/tet:label-start/tet:te-label
               /tet:technology:
       +--:(example)
          +--ro example
             +--ro label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:information-source-entry/tet:connectivity-matrices
               /tet:connectivity-matrix/tet:from/tet:label-restrictions
               /tet:label-restriction/tet:label-end/tet:te-label
               /tet:technology:
       +--:(example)
          +--ro example
             +--ro label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:information-source-entry/tet:connectivity-matrices
               /tet:connectivity-matrix/tet:to/tet:label-restrictions
               /tet:label-restriction/tet:label-start/tet:te-label
               /tet:technology:
       +--:(example)
          +--ro example
             +--ro label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:information-source-entry/tet:connectivity-matrices
               /tet:connectivity-matrix/tet:to/tet:label-restrictions
               /tet:label-restriction/tet:label-end/tet:te-label
               /tet:technology:
       +--:(example)
          +--ro example
             +--ro label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:information-source-entry/tet:connectivity-matrices
               /tet:connectivity-matrix/tet:underlay/tet:primary-path
               /tet:path-element/tet:type/tet:label/tet:label-hop
               /tet:te-label/tet:technology:
       +--:(example)
          +--ro example
             +--ro label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:information-source-entry/tet:connectivity-matrices
               /tet:connectivity-matrix/tet:underlay/tet:backup-path
               /tet:path-element/tet:type/tet:label/tet:label-hop
               /tet:te-label/tet:technology:
       +--:(example)
          +--ro example
             +--ro label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:information-source-entry/tet:connectivity-matrices
               /tet:connectivity-matrix/tet:path-properties
               /tet:path-route-objects/tet:path-route-object/tet:type
               /tet:label/tet:label-hop/tet:te-label/tet:technology:
       +--:(example)
          +--ro example
             +--ro label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:tunnel-termination-point
               /tet:local-link-connectivities/tet:label-restrictions
               /tet:label-restriction/tet:label-start/tet:te-label
               /tet:technology:
       +--:(example)
          +--rw example
             +--rw label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:tunnel-termination-point
               /tet:local-link-connectivities/tet:label-restrictions
               /tet:label-restriction/tet:label-end/tet:te-label
               /tet:technology:
       +--:(example)
          +--rw example
             +--rw label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:tunnel-termination-point
               /tet:local-link-connectivities/tet:underlay
               /tet:primary-path/tet:path-element/tet:type/tet:label
               /tet:label-hop/tet:te-label/tet:technology:
       +--:(example)
          +--rw example
             +--rw label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:tunnel-termination-point
               /tet:local-link-connectivities/tet:underlay
               /tet:backup-path/tet:path-element/tet:type/tet:label
               /tet:label-hop/tet:te-label/tet:technology:
       +--:(example)
          +--rw example
             +--rw label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:tunnel-termination-point
               /tet:local-link-connectivities/tet:path-properties
               /tet:path-route-objects/tet:path-route-object/tet:type
               /tet:label/tet:label-hop/tet:te-label/tet:technology:
       +--:(example)
          +--ro example
             +--ro label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:tunnel-termination-point
               /tet:local-link-connectivities
               /tet:local-link-connectivity/tet:label-restrictions
               /tet:label-restriction/tet:label-start/tet:te-label
               /tet:technology:
       +--:(example)
          +--rw example
             +--rw label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:tunnel-termination-point
               /tet:local-link-connectivities
               /tet:local-link-connectivity/tet:label-restrictions
               /tet:label-restriction/tet:label-end/tet:te-label
               /tet:technology:
       +--:(example)
          +--rw example
             +--rw label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:tunnel-termination-point
               /tet:local-link-connectivities
               /tet:local-link-connectivity/tet:underlay
               /tet:primary-path/tet:path-element/tet:type/tet:label
               /tet:label-hop/tet:te-label/tet:technology:
       +--:(example)
          +--rw example
             +--rw label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:tunnel-termination-point
               /tet:local-link-connectivities
               /tet:local-link-connectivity/tet:underlay/tet:backup-path
               /tet:path-element/tet:type/tet:label/tet:label-hop
               /tet:te-label/tet:technology:
       +--:(example)
          +--rw example
             +--rw label-1?   uint32
     augment /nw:networks/nw:network/nw:node/tet:te
               /tet:tunnel-termination-point
               /tet:local-link-connectivities
               /tet:local-link-connectivity/tet:path-properties
               /tet:path-route-objects/tet:path-route-object/tet:type
               /tet:label/tet:label-hop/tet:te-label/tet:technology:
       +--:(example)
          +--ro example
             +--ro label-1?   uint32
     augment /nw:networks/nw:network/nt:link/tet:te
               /tet:te-link-attributes/tet:label-restrictions
               /tet:label-restriction/tet:label-start/tet:te-label
               /tet:technology:
       +--:(example)
          +--rw example
             +--rw label-1?   uint32
     augment /nw:networks/nw:network/nt:link/tet:te
               /tet:te-link-attributes/tet:label-restrictions
               /tet:label-restriction/tet:label-end/tet:te-label
               /tet:technology:
       +--:(example)
          +--rw example
             +--rw label-1?   uint32
     augment /nw:networks/nw:network/nt:link/tet:te
               /tet:te-link-attributes/tet:underlay/tet:primary-path
               /tet:path-element/tet:type/tet:label/tet:label-hop
               /tet:te-label/tet:technology:
       +--:(example)
          +--rw example
             +--rw label-1?   uint32
     augment /nw:networks/nw:network/nt:link/tet:te
               /tet:te-link-attributes/tet:underlay/tet:backup-path
               /tet:path-element/tet:type/tet:label/tet:label-hop
               /tet:te-label/tet:technology:
       +--:(example)
          +--rw example
             +--rw label-1?   uint32
     augment /nw:networks/nw:network/nt:link/tet:te
               /tet:information-source-entry/tet:label-restrictions
               /tet:label-restriction/tet:label-start/tet:te-label
               /tet:technology:
       +--:(example)
          +--ro example
             +--ro label-1?   uint32
     augment /nw:networks/nw:network/nt:link/tet:te
               /tet:information-source-entry/tet:label-restrictions
               /tet:label-restriction/tet:label-end/tet:te-label
               /tet:technology:
       +--:(example)
          +--ro example
             +--ro label-1?   uint32

Пример модуля YANG, реализующего описанную выше топологию, представлен в Приложении C.

7. Модуль YANG для топологии TE

Этот модуль упоминает [RFC1195], [RFC3209], [RFC3272], [RFC3471], [RFC3630], [RFC3785], [RFC4201], [RFC4202], [RFC4203], [RFC4206], [RFC4872], [RFC5152], [RFC5212], [RFC5305], [RFC5316], [RFC5392], [RFC6001], [RFC6241], [RFC6991], [RFC7308], [RFC7471], [RFC7579], [RFC7752], [RFC8345], [RFC8776].

   <CODE BEGINS> file "ietf-te-topology@2020-08-06.yang"
   module ietf-te-topology {
     yang-version 1.1;
     namespace "urn:ietf:params:xml:ns:yang:ietf-te-topology";
     prefix tet;

     import ietf-yang-types {
       prefix yang;
       reference
         "RFC 6991: Common YANG Data Types";
     }
     import ietf-inet-types {
       prefix inet;
       reference
         "RFC 6991: Common YANG Data Types";
     }
     import ietf-te-types {
       prefix te-types;
       reference
         "RFC 8776: Common YANG Data Types for Traffic Engineering";
     }
     import ietf-network {
       prefix nw;
       reference
         "RFC 8345: A YANG Data Model for Network Topologies";
     }
     import ietf-network-topology {
       prefix nt;
       reference
         "RFC 8345: A YANG Data Model for Network Topologies";
     }

     organization
       "IETF Traffic Engineering Architecture and Signaling (TEAS)
        Working Group";
     contact
       "WG Web:   <https://datatracker.ietf.org/wg/teas/> 
        WG List:  <mailto:teas@ietf.org> 

        Editor:   Xufeng Liu
                  <mailto:xufeng.liu.ietf@gmail.com> 

        Editor:   Igor Bryskin
                  <mailto:i_bryskin@yahoo.com> 

        Editor:   Vishnu Pavan Beeram
                  <mailto:vbeeram@juniper.net> 

        Editor:   Tarek Saad
                  <mailto:tsaad@juniper.net> 

        Editor:   Himanshu Shah
                  <mailto:hshah@ciena.com> 

        Editor:   Oscar Gonzalez de Dios
                  <mailto:oscar.gonzalezdedios@telefonica.com>"; 
     description
       "Этот модуль YANG задаёт модель топологии TE для представления,
        извлечения и манипуляций с независимой от технологии топологией
        TE.

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

        Распространение и использование в исходной или двоичной форме с
        изменениями или без таковых разрешено в соответствии с лицензией
        Simplified BSD, изложенной в разделе 4  IETF Trust's Legal
        Provisions применительно к документам IETF
        (http://trustee.ietf.org/license-info). 

        Эта версия данного модуля YANG является частью RFC 8795, где
        правовые вопросы рассмотрены более полно.";

     revision 2020-08-06 {
       description
         "Исходный выпуск.";
       reference
         "RFC 8795: YANG Data Model for Traffic Engineering (TE)
          Topologies";
     }

     /*
      * Свойства
      */

     feature nsrlg {
       description
         "Это свойство указывает, что система поддерживает NSRLG
          (Non-Shared Risk Link Groups).";
     }

     feature te-topology-hierarchy {
       description
         "Это свойство показывает, что система разрешает базовую и/или
          наложенную иерархию топологии TE.";
     }

     feature template {
       description
         "Это свойство указывает, что система поддерживает настройку
          шаблонов.";
     }

     /*
      * Определения типов
      */

     typedef geographic-coordinate-degree {
       type decimal64 {
         fraction-digits 8;
       }
       description
         "Десятичные градусы (DD) служат для указания географических
          координат.";
     }
     // Градусы географических координат

     typedef te-info-source {
       type enumeration {
         enum unknown {
           description
             "Источник неизвестен.";
         }
         enum locally-configured {
           description
             "Настроенный элемент.";
         }
         enum ospfv2 {
           description
             "OSPFv2.";
         }
         enum ospfv3 {
           description
             "OSPFv3.";
         }
         enum isis {
           description
             "IS-IS.";
         }
         enum bgp-ls {
           description
             "BGP-LS.";
           reference
             "RFC 7752: North-Bound Distribution of Link-State and
              Traffic Engineering (TE) Information Using BGP";
         }
         enum system-processed {
           description
             "Обрабатываемый системой элемент.";
         }
         enum other {
           description
             "Иной источник.";
         }
       }
       description
         "Описывает тип источника информации и его достоверность.";
     }
     // te-info-source

     /*
      * Группировки
      */

     grouping connectivity-matrix-entry-path-attributes {
       description
         "Атрибуты записи матрицы связности.";
       leaf is-allowed {
         type boolean;
         description
           "'true' - переключение разрешено;
            'false' - переключение не разрешено.";
       }
       container underlay {
         if-feature "te-topology-hierarchy";
         description
           "Атрибуты базового канала TE.";
         reference
           "RFC 4206: Label Switched Paths (LSP) Hierarchy with
            Generalized Multi-Protocol Label Switching (GMPLS)
            Traffic Engineering (TE)";
         uses te-link-underlay-attributes;
       }
       uses te-types:generic-path-constraints;
       uses te-types:generic-path-optimization;
       uses te-types:generic-path-properties;
     }
     // Атрибуты пути записи матрицы связности

     grouping geolocation-container {
       description
         "Координаты GPS.";
       container geolocation {
         config false;
         description
           "Координаты GPS .";
         leaf altitude {
           type int64;
           units "millimeters";
           description
             "Высота над уровнем моря.";
         }
         leaf latitude {
           type geographic-coordinate-degree {
             range "-90..90";
           }
           description
             "Градусы широты.";
         }
         leaf longitude {
           type geographic-coordinate-degree {
             range "-180..180";
           }
           description
             "Градусы долготы.";
         }
       }
       // Географическое положение
     }
     // Контейнер географического положения

     grouping information-source-state-attributes {
       description
         "Атрибуты источника сведений и его достоверности.";
       leaf credibility-preference {
         type uint16;
         description
           "Значение предпочтительности для расчёта достоверности базы
            данных TE, используемое для выбора источника сведений.
            Большее значение указывает предпочтительность.";
       }
       leaf logical-network-element {
         type string;
         description
           "Имя логического логического элемента сети, от которого
            берутся сведения (когда это применимо).";
       }
       leaf network-instance {
         type string;
         description
           "Имя экземпляра сети, от которого берутся сведения 
            (когда это применимо).";
       }
     }
     // Атрибуты состояния источника сведений

     grouping information-source-per-link-attributes {
       description
         "Контейнер на уровне канала с атрибутами, указывающими
          источник сведений и его достоверность.";
       leaf information-source {
         type te-info-source;
         config false;
         description
           "Тип источника информации.";
       }
       leaf information-source-instance {
         type string;
         config false;
         description
           "Имя, указывающее экземпляр источника сведений.";
       }
       container information-source-state {
         config false;
         description
           "Атрибуты состояния источника сведений.";
         uses information-source-state-attributes;
         container topology {
           description
             "При обработке информации системой атрибуты в этом 
              контейнере указывают, какая топология применяется
              для создания результирующих сведений.";
           uses nt:link-ref;
         }
       }
     }
     // Атрибуты источника по каналам

     grouping information-source-per-node-attributes {
       description
         "Контейнер на уровне узла с атрибутами, указывающими
          источник сведений и его достоверность.";
       leaf information-source {
         type te-info-source;
         config false;
         description
           "Тип источника информации.";
       }
       leaf information-source-instance {
         type string;
         config false;
         description
           "Имя, указывающее экземпляр источника сведений.";
       }
       container information-source-state {
         config false;
         description
           "Атрибуты состояния источника сведений.";
         uses information-source-state-attributes;
         container topology {
           description
             "При обработке информации системой атрибуты в этом 
              контейнере указывают, какая топология применяется
              для создания результирующих сведений.";
           uses nw:node-ref;
         }
       }
     }
     // Атрибуты источника по узлам

     grouping interface-switching-capability-list {
       description
         "Список дескрипторов возможностей коммутации (ISCD).";
       list interface-switching-capability {
         key "switching-capability encoding";
         description
           "Список ISCD для канала.";
         reference
           "RFC 3471: Generalized Multi-Protocol Label Switching (GMPLS)
            Signaling Functional Description
            RFC 4203: OSPF Extensions in Support of Generalized
            Multi-Protocol Label Switching (GMPLS)";
         leaf switching-capability {
           type identityref {
             base te-types:switching-capabilities;
           }
           description
             "Возможности коммутации для интерфейса.";
         }
         leaf encoding {
           type identityref {
             base te-types:lsp-encoding-types;
           }
           description
             "Кодирование, поддерживаемое интерфейсом.";
         }
         uses te-link-iscd-attributes;
       }
       // Возможности коммутации на интерфейсе
     }
     // Список возможностей коммутации

     grouping statistics-per-link {
       description
         "Атрибуты статистики на канал TE.";
       leaf discontinuity-time {
         type yang:date-and-time;
         description
           "Время последнего разрыва одного или нескольких счётчиков на
            данном интерфейсе. Если разрывов после предыдущей 
            инициализации локальной подсистемы управления не было, узел
            содержит время инициализации этой подсистемы.";
       }
       /* Административные атрибуты */
       leaf disables {
         type yang:counter32;
         description
           "Число случаев отключения канала.";
       }
       leaf enables {
         type yang:counter32;
         description
           "Число случаев включения канала.";
       }
       leaf maintenance-clears {
         type yang:counter32;
         description
           "Число случаев снятия канала с обслуживания.";
       }
       leaf maintenance-sets {
         type yang:counter32;
         description
           "Число случаев постановки канала на обслуживание.";
       }
       leaf modifies {
         type yang:counter32;
         description
           "Число случаев изменения канала.";
       }
       /* Рабочие атрибуты */
       leaf downs {
         type yang:counter32;
         description
           "Число случаев установки для канала состояния down.";
       }
       leaf ups {
         type yang:counter32;
         description
           "Число случаев установки для канала состояния up.";
       }
       /* Атрибуты восстановления */
       leaf fault-clears {
         type yang:counter32;
         description
           "Число событий очистки отказов на канале.";
       }
       leaf fault-detects {
         type yang:counter32;
         description
           "Число обнаружений отказов на канале.";
       }
       leaf protection-switches {
         type yang:counter32;
         description
           "Число защитных переключений на канале.";
       }
       leaf protection-reverts {
         type yang:counter32;
         description
           "Число возвратных защитных переключений на канале.";
       }
       leaf restoration-failures {
         type yang:counter32;
         description
           "Число отказов при восстановлении на канале.";
       }
       leaf restoration-starts {
         type yang:counter32;
         description
           "Число запусков восстановления на канале.";
       }
       leaf restoration-successes {
         type yang:counter32;
         description
           "Число случаев успешного восстановления на канале.";
       }
       leaf restoration-reversion-failures {
         type yang:counter32;
         description
           "Число отказов при восстановлении на канале.";
       }
       leaf restoration-reversion-starts {
         type yang:counter32;
         description
           "Число случаев запуска восстановления на канале.";
       }
       leaf restoration-reversion-successes {
         type yang:counter32;
         description
           "Число случаев успешного возвратного восстановления 
            на канале.";
       }
     }
     // Статистика по каналам

     grouping statistics-per-node {
       description
         "Атрибуты статистики на узел TE.";
       leaf discontinuity-time {
         type yang:date-and-time;
         description
           "Время последнего разрыва одного или нескольких счётчиков на
            данном интерфейсе. Если разрывов после предыдущей 
            инициализации локальной подсистемы управления не было, узел
            содержит время инициализации этой подсистемы.";
       }
       container node {
         description
           "Атрибуты статистики на уровне узла TE.";
         leaf disables {
           type yang:counter32;
           description
             "Число случаев отключения узла.";
         }
         leaf enables {
           type yang:counter32;
           description
             "Число случаев включения узла.";
         }
         leaf maintenance-sets {
           type yang:counter32;
           description
             "Число случаев перевода узла в обслуживание.";
         }
         leaf maintenance-clears {
           type yang:counter32;
           description
             "Число случаев исключения узла из обслуживания.";
         }
         leaf modifies {
           type yang:counter32;
           description
             "Число случаев изменения узла.";
         }
       }
       // Узел
       container connectivity-matrix-entry {
         description
           "Атрибуты статистики на уровне записи матрицы связности.";
         leaf creates {
           type yang:counter32;
           description
             "Число случаев создания записей матрицы связности.";
           reference
             "RFC 6241: Network Configuration Protocol (NETCONF),
                        Section 7.2, 'create' operation";
         }
         leaf deletes {
           type yang:counter32;
           description
             "Число случаев удаления записей матрицы связности.";
           reference
             "RFC 6241: Network Configuration Protocol (NETCONF),
                        Section 7.2, 'delete' operation";
         }
         leaf disables {
           type yang:counter32;
           description
             "Число случаев отключения записей матрицы связности.";
         }
         leaf enables {
           type yang:counter32;
           description
             "Число случаев включения записей матрицы связности.";
         }
         leaf modifies {
           type yang:counter32;
           description
             "Число случаев изменения записей матрицы связности.";
         }
       }
       // Запись матрицы связности
     }
     // Статистика на узел

     grouping statistics-per-ttp {
       description
         "Атрибуты статистики TE TTP (Tunnel Termination Point).";
       leaf discontinuity-time {
         type yang:date-and-time;
         description
           "Время последнего разрыва одного или нескольких счётчиков на
            данном интерфейсе. Если разрывов после предыдущей 
            инициализации локальной подсистемы управления не было, узел
            содержит время инициализации этой подсистемы.";
       }
       container tunnel-termination-point {
         description
           "Атрибуты статистики на уровне TE TTP.";
         /* Административные атрибуты. */
         leaf disables {
           type yang:counter32;
           description
             "Число случаев отключения TTP.";
         }
         leaf enables {
           type yang:counter32;
           description
             "Число случаев включения TTP.";
         }
         leaf maintenance-clears {
           type yang:counter32;
           description
             "Число случаев вывода TTP из обслуживания.";
         }
         leaf maintenance-sets {
           type yang:counter32;
           description
             "Число случаев ввода TTP в обслуживание.";
         }
         leaf modifies {
           type yang:counter32;
           description
             "Число случаев изменения TTP.";
         }
         /* Рабочие атрибуты. */
         leaf downs {
           type yang:counter32;
           description
             "Число случаев перевода TTP в рабочее состояние down.";
         }
         leaf ups {
           type yang:counter32;
           description
             "Число случаев перевода TTP в рабочее состояние up.";
         }
         leaf in-service-clears {
           type yang:counter32;
           description
             "Число случаев вывода TTP из обслуживания 
              (освобождение туннеля TE).";
         }
         leaf in-service-sets {
           type yang:counter32;
           description
             "Число случаев ввода TTP в обслуживание туннелем TE
              (организация туннеля TE).";
         }
       }
       // Точка завершения туннеля
       container local-link-connectivity {
         description
           "Атрибуты статистики на уровне TE LLCL (Local Link
            Connectivity List).";
         leaf creates {
           type yang:counter32;
           description
             "Число случаев создания записей LLCL.";
           reference
             "RFC 6241: Network Configuration Protocol (NETCONF),
                        Section 7.2, 'create' operation";
         }
         leaf deletes {
           type yang:counter32;
           description
             "Число случаев удаления записей LLCL.";
           reference
             "RFC 6241: Network Configuration Protocol (NETCONF),
                        Section 7.2, 'delete' operation";
         }
         leaf disables {
           type yang:counter32;
           description
             "Число случаев отключения записей LLCL.";
         }
         leaf enables {
           type yang:counter32;
           description
             "Число случаев включения записей LLCL.";
         }
         leaf modifies {
           type yang:counter32;
           description
             "Число случаев изменения записей LLCL.";
         }
       }
       // Связность на локальном канале
     }
     // Статистика по TTP

     grouping te-link-augment {
       description
         "Дополнение для канала TE.";
       uses te-link-config;
       uses te-link-state-derived;
       container statistics {
         config false;
         description
           "Данные статистики.";
         uses statistics-per-link;
       }
     }
     // Дополнение для канала TE.

     grouping te-link-config {
       description
         "Группировка конфигурации канала TE.";
       choice bundle-stack-level {
         description
           "Канал TE может состоять из связанных или композитных
            каналов.";
         case bundle {
           container bundled-links {
             description
               "Набор связанных (bundle) каналов.";
             reference
               "RFC 4201: Link Bundling in MPLS Traffic
                Engineering (TE)";
             list bundled-link {
               key "sequence";
               description
                 "Указывает связанный интерфейс, который делится еще.";
               leaf sequence {
                 type uint32;
                 description
                   "Указывает порядок в связке (bundle).";
               }
             }
           }
         }
         case component {
           container component-links {
             description
               "Набор компонентных каналов.";
             list component-link {
               key "sequence";
               description
                 "Указывает компонентный интерфейс, которого достаточно 
                  для однозначной идентификации соответствующих 
                  ресурсов.";
               leaf sequence {
                 type uint32;
                 description
                   "Указывает порядок в связке (bundle).";
               }
               leaf src-interface-ref {
                 type string;
                 description
                   "Указывает интерфейс композитного канала на 
                    узле-источнике.";
               }
               leaf des-interface-ref {
                 type string;
                 description
                   "Указывает интерфейс композитного канала на 
                    целевом узле.";
               }
             }
           }
         }
       }
       // Уровень связки каналов
       leaf-list te-link-template {
         if-feature "template";
         type leafref {
           path "../../../../te/templates/link-template/name";
         }
         description
           "Ссылка на шаблон канала TE.";
       }
       uses te-link-config-attributes;
     }
     // Конфигурация канала TE.

     grouping te-link-config-attributes {
       description
         "Конфигурационные атрибуты канала в топологии TE.";
       container te-link-attributes {
         description
           "Атрибуты канала в топологии TE.";
         leaf access-type {
           type te-types:te-link-access-type;
           description
             "Тип доступа к каналу (точка-точка или многоточечный.";
         }
         container external-domain {
           description
             "Для междоменного канала задаёт атрибуты удалённого конца
              для упрощения сигнализации на локальном конце.";
           uses nw:network-ref;
           leaf remote-te-node-id {
             type te-types:te-node-id;
             description
               "Идентификатор удалённого узла TE, используемый вместе с
                remote-te-link-tp-id для указания удалённой точки
                завершения канала (LTP) в другом домене.";
           }
           leaf remote-te-link-tp-id {
             type te-types:te-tp-id;
             description
               "Идентификатор удалённой точки TE LTP, используемый 
                вместе с remote-te-node-id для указания удалённой LTP
                в другом домене.";
           }
         }
         leaf is-abstract {
           type empty;
           description
             "Присутствует для абстрактного канала.";
         }
         leaf name {
           type string;
           description
             "Имя канала.";
         }
         container underlay {
           if-feature "te-topology-hierarchy";
           description
             "Атрибуты основы канала TE (underlay).";
           reference
             "RFC 4206: Label Switched Paths (LSP) Hierarchy with
              Generalized Multi-Protocol Label Switching (GMPLS)
              Traffic Engineering (TE)";
           uses te-link-underlay-attributes;
         }
         leaf admin-status {
           type te-types:te-admin-status;
           description
             "Административное состояние канала.";
         }
         uses te-link-info-attributes;
       }
       // Атрибуты канала TE.
     }
     // Атрибуты конфигурации канала TE.

     grouping te-link-info-attributes {
       description
         "Анонсируемые атрибуты сведений TE.";
       leaf link-index {
         type uint64;
         description
           "Идентификатор канала. При использовании OSPF этот объект
            представляет ospfLsdbID, при использовании IS-IS - 
            isisLSPID. При использовании локально настроенного канала
            объект представляет уникальное значение, заданное 
            локально в маршрутизаторе.";
       }
       leaf administrative-group {
         type te-types:admin-groups;
         description
           "Административная группа или цвет канала. Атрибут охватывает
            как административные группы RFC 3630 и RFC 5305, так и
            расширенные административные группы RFC 7308.";
         reference
           "RFC 3630: Traffic Engineering (TE) Extensions to OSPF
            Version 2
            RFC 5305: IS-IS Extensions for Traffic Engineering
            RFC 7308: Extended Administrative Groups in MPLS Traffic
            Engineering (MPLS-TE)";
       }
       uses interface-switching-capability-list;
       uses te-types:label-set-info;
       leaf link-protection-type {
         type identityref {
           base te-types:link-protection-type;
         }
         description
           "Желательный тип защиты для канала.";
         reference
           "RFC 4202: Routing Extensions in Support of
            Generalized Multi-Protocol Label Switching (GMPLS)";
       }
       container max-link-bandwidth {
         uses te-types:te-bandwidth;
         description
           "Максимальная пропускная способность, которую можно видеть на
            канале в этом направлении (байт/сек).";
         reference
           "RFC 3630: Traffic Engineering (TE) Extensions to OSPF
            Version 2
            RFC 5305: IS-IS Extensions for Traffic Engineering";
       }
       container max-resv-link-bandwidth {
         uses te-types:te-bandwidth;
         description
           "Максимальная пропускная способность, которую можно 
            зарезервировать на канале в этом направлении (байт/сек).";
         reference
           "RFC 3630: Traffic Engineering (TE) Extensions to OSPF
            Version 2
            RFC 5305: IS-IS Extensions for Traffic Engineering";
       }
       list unreserved-bandwidth {
         key "priority";
         max-elements 8;
         description
           "Незарезервированная пропускная способность для уровней 
            приоритета 0 - 7 (байт/сек).";
         reference
           "RFC 3630: Traffic Engineering (TE) Extensions to OSPF
            Version 2
            RFC 5305: IS-IS Extensions for Traffic Engineering";
         leaf priority {
           type uint8 {
             range "0..7";
           }
           description
             "Приоритет.";
         }
         uses te-types:te-bandwidth;
       }
       leaf te-default-metric {
         type uint32;
         description
           "Метрика TE.";
         reference
           "RFC 3630: Traffic Engineering (TE) Extensions to OSPF
            Version 2
            RFC 5305: IS-IS Extensions for Traffic Engineering";
       }
       leaf te-delay-metric {
         type uint32;
         description
           "Метрика задержки TE.";
         reference
           "RFC 7471: OSPF Traffic Engineering (TE) Metric Extensions";
       }
       leaf te-igp-metric {
         type uint32;
         description
           "Метрика IGP для TE.";
         reference
           "RFC 3785: Use of Interior Gateway Protocol (IGP) Metric as a
            second MPLS Traffic Engineering (TE) Metric";
       }
       container te-srlgs {
         description
           "Список SRLG.";
         leaf-list value {
           type te-types:srlg;
           description
             "Значение SRLG.";
           reference
             "RFC 4202: Routing Extensions in Support of
              Generalized Multi-Protocol Label Switching (GMPLS)";
         }
       }
       container te-nsrlgs {
         if-feature "nsrlg";
         description
           "Список NSRLG (Non-Shared Risk Link Group). Когда настроен
            абстрактный канал TE, этот список запрашивает, чтобы базовые
            пути TE были взаимно развязаны с другими каналами TE тех же
            групп.";
         leaf-list id {
           type uint32;
           description
             "Уникальный идентификатор NSRLG в рамках топологии.";
           reference
             "RFC 4872: RSVP-TE Extensions in Support of End-to-End
              Generalized Multi-Protocol Label Switching (GMPLS)
              Recovery";
         }
       }
     }
     // Атрибуты сведений о канале TE

     grouping te-link-iscd-attributes {
       description
         "Атрибуты ISCD канала TE.";
       reference
         "RFC 4203: OSPF Extensions in Support of Generalized
          Multi-Protocol Label Switching (GMPLS), Section 1.4";
       list max-lsp-bandwidth {
         key "priority";
         max-elements 8;
         description
           "Максимальная пропускная способность LSP для приоритета
            0-7.";
         leaf priority {
           type uint8 {
             range "0..7";
           }
           description
             "Приоритет.";
         }
         uses te-types:te-bandwidth;
       }
     }
     // Атрибуты ISCD канала TE.

     grouping te-link-state-derived {
       description
         "Атрибуты состояния канала в топологии TE.";
       leaf oper-status {
         type te-types:te-oper-status;
         config false;
         description
           "Текущее рабочее состояние канала.";
       }
       leaf is-transitional {
         type empty;
         config false;
         description
           "Присутствует для временного канала и применяется как
            альтернатива inter-layer-lock-id для расчёта пути в 
            топологии TE охватывающей несколько уровней или областей.";
         reference
           "RFC 5212: Requirements for GMPLS-Based Multi-Region and
            Multi-Layer Networks (MRN/MLN)
            RFC 6001: Generalized MPLS (GMPLS) Protocol Extensions
            for Multi-Layer and Multi-Region Networks (MLN/MRN)";
       }
       uses information-source-per-link-attributes;
       list information-source-entry {
         key "information-source information-source-instance";
         config false;
         description
           "Список изученных источников сведений, включая используемые.";
         uses information-source-per-link-attributes;
         uses te-link-info-attributes;
       }
       container recovery {
         config false;
         description
           "Статус процесса восстановления.";
         leaf restoration-status {
           type te-types:te-recovery-status;
           description
             "Статус восстановления.";
         }
         leaf protection-status {
           type te-types:te-recovery-status;
           description
             "Статус защиты.";
         }
       }
       container underlay {
         if-feature "te-topology-hierarchy";
         config false;
         description
           "Атрибуты состояния основы канала TE.";
         leaf dynamic {
           type boolean;
           description
             "true, если основа создана динамически.";
         }
         leaf committed {
           type boolean;
           description
             "true, если основа зафиксирована.";
         }
       }
     }
     // Выведенное состояние канала TE

     grouping te-link-underlay-attributes {
       description
         "Атрибуты основы канала TE.";
       reference
         "RFC 4206: Label Switched Paths (LSP) Hierarchy with
          Generalized Multi-Protocol Label Switching (GMPLS)
          Traffic Engineering (TE)";
       leaf enabled {
         type boolean;
         description
           "true, если основа включена, иначе false.";
       }
       container primary-path {
         description
           "Путь услуги в базовой топологии, поддерживающей канал.";
         uses nw:network-ref;
         list path-element {
           key "path-element-id";
           description
             "Список элементов, описывающих путь услуги.";
           leaf path-element-id {
             type uint32;
             description
               "Идентификатор элемента пути.";
           }
           uses te-path-element;
         }
       }
       // Первичный путь
       list backup-path {
         key "index";
         description
           "Список резервных путей услуги в базовой топологии для защиты
            основного базового пути. Если основной путь не защищён,
            список будет пустым, иначе включает один или несколько
            элементов.";
         leaf index {
           type uint32;
           description
             "Порядковый номер для идентификации резервного пути.";
         }
         uses nw:network-ref;
         list path-element {
           key "path-element-id";
           description
             "Список элементов, описывающих резервный путь услуги.";
           leaf path-element-id {
             type uint32;
             description
               "Идентификатор элемента пути.";
           }
           uses te-path-element;
         }
       }
       // Резервный путь
       leaf protection-type {
         type identityref {
           base te-types:lsp-protection-type;
         }
         description
           "Желательный тип защиты основы для канала.";
       }
       container tunnel-termination-points {
         description
           "Желательные базовые TTP для канала.";
         leaf source {
           type binary;
           description
             "Идентификатор TTP-источника.";
         }
         leaf destination {
           type binary;
           description
             "Идентификатор целевого TTP.";
         }
       }
       container tunnels {
         description
           "Базовые туннели TE, поддерживающие канал TE.";
         leaf sharing {
           type boolean;
           default "true";
           description
             "true, если базовый туннель может разделяться с другими
              каналами TE, false, если базовый туннель выделен для этого
              канала TE. Этот лист принят по умолчанию для всех туннелей
              TE и может быть переопределен на уровне туннеля.";
         }
         list tunnel {
           key "tunnel-name";
           description
             "Туннели TE (возможно 0), поддерживающие этот канал TE.";
           leaf tunnel-name {
             type string;
             description
               "Имя, однозначно указывающее базовый туннель TE, которое
                используется вместе с source-node для канала.";
             reference
               "RFC 3209: RSVP-TE: Extensions to RSVP for LSP Tunnels";
           }
           leaf sharing {
             type boolean;
             description
             "true, если базовый туннель может разделяться с другими
              каналами TE, false, если базовый туннель выделен для этого
              канала TE.";
           }
         }
         // Туннель
       }
       // Туннели
     }
     // Атрибуты базового канала TE

     grouping te-node-augment {
       description
         "Дополнение для узла TE.";
       uses te-node-config;
       uses te-node-state-derived;
       container statistics {
         config false;
         description
           "Данные статистики.";
         uses statistics-per-node;
       }
       list tunnel-termination-point {
         key "tunnel-tp-id";
         description
           "Точка завершения может быть окончанием туннеля.";
         leaf tunnel-tp-id {
           type binary;
           description
             "Идентификатор TTP.";
         }
         uses te-node-tunnel-termination-point-config;
         leaf oper-status {
           type te-types:te-oper-status;
           config false;
           description
             "Текущее рабочее состояние TTP.";
         }
         uses geolocation-container;
         container statistics {
           config false;
           description
             "Данные статистики.";
           uses statistics-per-ttp;
         }
         // Связи с другими TTP
         list supporting-tunnel-termination-point {
           key "node-ref tunnel-tp-ref";
           description
             "TTP, от которых зависит эта точка TTP.";
           leaf node-ref {
             type inet:uri;
             description
               "Указывает узел с поддерживающей точкой TTP. 
                Это поддерживающий узел или узел базовой топологии.";
           }
           leaf tunnel-tp-ref {
             type binary;
             description
               "Указывает точку TTP, которая является узлом поддержки
                или базовой топологии.";
           }
         }
         // Точка завершения поддерживающего туннеля
       }
       // Точка завершения туннеля
     }
     // Дополнение узла TE

     grouping te-node-config {
       description
         "Группировка конфигурации узла TE.";
       leaf-list te-node-template {
         if-feature "template";
         type leafref {
           path "../../../../te/templates/node-template/name";
         }
         description
           "Ссылка на шаблон узла TE.";
       }
       uses te-node-config-attributes;
     }
     // Конфигурация узла TE

     grouping te-node-config-attributes {
       description
         "Атрибуты конфигурации узла в топологии TE.";
       container te-node-attributes {
         description
           "Атрибуты узла в топологии TE.";
         leaf admin-status {
           type te-types:te-admin-status;
           description
             "Административное состояние канала.";
         }
         uses te-node-connectivity-matrices;
         uses te-node-info-attributes;
       }
     }
     // Атрибуты конфигурации узла TE.

     grouping te-node-config-attributes-template {
       description
         "Атрибуты конфигурации узла для шаблона в топологии TE.";
       container te-node-attributes {
         description
           "Атрибуты узла в топологии TE.";
         leaf admin-status {
           type te-types:te-admin-status;
           description
             "Административное состояние канала.";
         }
         uses te-node-info-attributes;
       }
     }
     // Шаблон атрибутов конфигурации узла

     grouping te-node-connectivity-matrices {
       description
         "Матрица связности узла TE.";
       container connectivity-matrices {
         description
           "Матрица связности на узле TE.";
         leaf number-of-entries {
           type uint16;
           description
             "Число записей матрицы связности. Если это число задано в
              запросе конфигурации, оно указывает количество запрошенных 
              записей, но в списке могут присутствовать не все. Если оно
              указано в данных состояния, это текущее количество рабочих
              записей.";
         }
         uses te-types:label-set-info;
         uses connectivity-matrix-entry-path-attributes;
         list connectivity-matrix {
           key "id";
           description
             "Ограничения коммутации на узле, т. е. соединения сетевых
              каналов TE через узел.";
           reference
             "RFC 7579: General Network Element Constraint Encoding
              for GMPLS-Controlled Networks";
           leaf id {
             type uint32;
             description
               "Указывает запись матрицы связности.";
           }
         }
         // Матрица связности.
       }
       // Матрицы связности.
     }
     // Матрицы связности узлов TE.

     grouping te-node-connectivity-matrix-attributes {
       description
         "Точка завершения указывает запись матрицы связности.";
       container from {
         description
           "Ссылка на LTP-источник.";
         leaf tp-ref {
           type leafref {
             path "../../../../../../nt:termination-point/nt:tp-id";
           }
           description
             "Относительная ссылка на точку завершения.";
         }
         uses te-types:label-set-info;
       }
       container to {
         description
           "Ссылка на целевую точку LTP.";
         leaf tp-ref {
           type leafref {
             path "../../../../../../nt:termination-point/nt:tp-id";
           }
           description
             "Относительная ссылка на точку завершения.";
         }
         uses te-types:label-set-info;
       }
       uses connectivity-matrix-entry-path-attributes;
     }
     // Атрибуты матрицы связности узла TE.

     grouping te-node-info-attributes {
       description
         "Атрибуты анонсируемых сведений TE.";
       leaf domain-id {
         type uint32;
         description
           "Указывает домен, к которому относится узел и служит для
            поддержки междоменных каналов.";
         reference
           "RFC 5152: A Per-Domain Path Computation Method for
            Establishing Inter-Domain Traffic Engineering (TE)
            Label Switched Paths (LSPs)
            RFC 5316: ISIS Extensions in Support of Inter-Autonomous
            System (AS) MPLS and GMPLS Traffic Engineering
            RFC 5392: OSPF Extensions in Support of Inter-Autonomous
            System (AS) MPLS and GMPLS Traffic Engineering";
       }
       leaf is-abstract {
         type empty;
         description
           "Присутствует лишь для абстрактных (не фактических) узлов.";
       }
       leaf name {
         type string;
         description
           "Имя узла.";
       }
       leaf-list signaling-address {
         type inet:ip-address;
         description
           "Сигнальный адрес узла.";
       }
       container underlay-topology {
         if-feature "te-topology-hierarchy";
         description
           "Когда абстрактный узел инкапсулирует топологию, атрибуты в
            этом контейнере указывают на данную топологию.";
         uses nw:network-ref;
       }
     }
     // Атрибуты сведений узла TE.

     grouping te-node-state-derived {
       description
         "Атрибуты состояния узла в топологии TE.";
       leaf oper-status {
         type te-types:te-oper-status;
         config false;
         description
           "Текущее рабочее состояние узла.";
       }
       uses geolocation-container;
       leaf is-multi-access-dr {
         type empty;
         config false;
         description
           "Наличие этого атрибута указывает, что данный узел TE 
            является псевдоузлом, выбранным в качестве указанного
            (designated) маршрутизатора.";
         reference
           "RFC 1195: Use of OSI IS-IS for Routing in TCP/IP and Dual
            Environments
            RFC 3630: Traffic Engineering (TE) Extensions to OSPF
            Version 2";
       }
       uses information-source-per-node-attributes;
       list information-source-entry {
         key "information-source information-source-instance";
         config false;
         description
           "Список изученных источников информации, включая 
            используемый.";
         uses information-source-per-node-attributes;
         uses te-node-connectivity-matrices;
         uses te-node-info-attributes;
       }
     }
     // Выведенное состояние узла TE.

     grouping te-node-tunnel-termination-point-config {
       description
         "Termination capability of a TTP on a TE node.";
       uses te-node-tunnel-termination-point-config-attributes;
       container local-link-connectivities {
         description
           "LLCL для TTP на узле TE.";
         leaf number-of-entries {
           type uint16;
           description
             "Число записей LLCL. В запросе конфигурации указывает
              число запрошенных записей, но не все могут не включаться
              в список. В данных состояния указывает текущее число 
              рабочих записей .";
         }
         uses te-types:label-set-info;
         uses connectivity-matrix-entry-path-attributes;
       }
     }
     // Конфигурация точки завершения туннеля на узле TE.

     grouping te-node-tunnel-termination-point-config-attributes {
       description
         "Атрибуты конфигурации TTP на узле TE.";
       leaf admin-status {
         type te-types:te-admin-status;
         description
           "Административный статус TTP.";
       }
       leaf name {
         type string;
         description
           "Описательное имя TTP.";
       }
       leaf switching-capability {
         type identityref {
           base te-types:switching-capabilities;
         }
         description
           "Возможности коммутации для интерфейса.";
       }
       leaf encoding {
         type identityref {
           base te-types:lsp-encoding-types;
         }
         description
           "Поддерживаемое интерфейсом кодирование.";
       }
       leaf-list inter-layer-lock-id {
         type uint32;
         description
           "Идентификатор межуровневой блокировки, применяемый для 
            расчёта пути в топологии TE, охватывающей не один уровень
            или область.";
         reference
           "RFC 5212: Requirements for GMPLS-Based Multi-Region and
            Multi-Layer Networks (MRN/MLN)
            RFC 6001: Generalized MPLS (GMPLS) Protocol Extensions
            for Multi-Layer and Multi-Region Networks (MLN/MRN)";
       }
       leaf protection-type {
         type identityref {
           base te-types:lsp-protection-type;
         }
         description
           "Тип защиты, поддерживаемой этой точкой TTP.";
       }
       container client-layer-adaptation {
         description
           "Сведения о возможностях для поддержки адаптации клиентского
            уровня в многоуровневой топологии.";
         list switching-capability {
           key "switching-capability encoding";
           description
             "Список поддерживаемых возможностей коммутации.";
           reference
             "RFC 4202: Routing Extensions in Support of
              Generalized Multi-Protocol Label Switching (GMPLS)
              RFC 6001: Generalized MPLS (GMPLS) Protocol Extensions
              for Multi-Layer and Multi-Region Networks (MLN/MRN)";
           leaf switching-capability {
             type identityref {
               base te-types:switching-capabilities;
             }
             description
               "Возможность коммутации для адаптации уровня клиента.";
           }
           leaf encoding {
             type identityref {
               base te-types:lsp-encoding-types;
             }
             description
               "Кодирование, поддерживаемое адаптацией уровня клиента.";
           }
           uses te-types:te-bandwidth;
         }
       }
     }
     // Атрибуты конфигурации точки завершения туннеля на узле TE.

     grouping te-node-tunnel-termination-point-llc-list {
       description
         "LLCL точки TTP на узле TE.";
       list local-link-connectivity {
         key "link-tp-ref";
         description
           "Возможности завершения между TTP и LTP. Эти сведения могут
            служить для расчёта пути туннеля. Дескрипторы возможности
            настройки интерфейса (IACD, RFC 6001) на каждой точке LTP
            могут быть выедены из этого списка.";
         reference
           "RFC 6001: Generalized MPLS (GMPLS) Protocol Extensions
            for Multi-Layer and Multi-Region Networks (MLN/MRN)";
         leaf link-tp-ref {
           type leafref {
             path "../../../../../nt:termination-point/nt:tp-id";
           }
           description
             "LTP.";
         }
         uses te-types:label-set-info;
         uses connectivity-matrix-entry-path-attributes;
       }
     }
     // Список LLC точки завершения туннеля на узле TE.

     grouping te-path-element {
       description
         "Группа атрибутов, определяющих элемент пути TE, таких как
          узел TE, канал TE, неделимый ресурс TE или метка.";
       uses te-types:explicit-route-hop;
     }
     // Элемент пути TE.

     grouping te-termination-point-augment {
       description
         "Дополнение для точки завершения TE.";
       leaf te-tp-id {
         type te-types:te-tp-id;
         description
           "Идентификатор, однозначно указывающий точку завершения TE.";
       }
       container te {
         must '../te-tp-id';
         presence "Поддержка TE.";
         description
           "Указывает поддержку TE.";
         uses te-termination-point-config;
         leaf oper-status {
           type te-types:te-oper-status;
           config false;
           description
             "Текущее рабочее состояние LTP.";
         }
         uses geolocation-container;
       }
     }
     // Дополнение для точки завершения TE.

     grouping te-termination-point-config {
       description
         "Группировка конфигурации точки завершения TE.";
       leaf admin-status {
         type te-types:te-admin-status;
         description
           "Административный статус LTP.";
       }
       leaf name {
         type string;
         description
           "Описательное имя для LTP.";
       }
       uses interface-switching-capability-list;
       leaf inter-domain-plug-id {
         type binary;
         description
           "Уникальное в масштабе сети число, указывающее соединение, 
            которое поддерживает междоменный канал TE. Это более гибкий
            вариант указания remote-te-node-id и remote-te-link-tp-id на
            канале TE, когда провайдеру не известны их значения или 
            нужно обеспечить клиенту гибкость для смешения и 
            сопоставления нескольких топологий.";
       }
       leaf-list inter-layer-lock-id {
         type uint32;
         description
           "Идентификатор межуровневой блокировки, используемый для
            расчёта пути в топологии TE, охватывающей несколько доменов
            или областей.";
         reference
           "RFC 5212: Requirements for GMPLS-Based Multi-Region and
            Multi-Layer Networks (MRN/MLN)
            RFC 6001: Generalized MPLS (GMPLS) Protocol Extensions
            for Multi-Layer and Multi-Region Networks (MLN/MRN)";
       }
     }
     // Конфигурация точки завершения TE.

     grouping te-topologies-augment {
       description
         "Дополнения для топологии TE.";
       container te {
         presence "Поддержка TE.";
         description
           "Указывает поддержку TE.";
         container templates {
           description
             "Параметры конфигурации шаблонов, применяемых для
              топологии TE.";
           list node-template {
             if-feature "template";
             key "name";
             leaf name {
               type te-types:te-template-name;
               description
                 "Имя для указания шаблона узла TE.";
             }
             description
               "Список шаблонов узла TE для определения обобществляемых
                и неоднократно используемых атрибутов узла TE.";
             uses template-attributes;
             uses te-node-config-attributes-template;
           }
           // Шаблон узла
           list link-template {
             if-feature "template";
             key "name";
             leaf name {
               type te-types:te-template-name;
               description
                 "Имя для указания шаблона канала TE.";
             }
             description
               "Список шаблонов канала TE для задания обобществляемых
                и неоднократно используемых атрибутов канала TE.";
             uses template-attributes;
             uses te-link-config-attributes;
           }
           // Шаблон канала
         }
         // Шаблоны
       }
       // TE
     }
     // Дополнение топологии TE.

     grouping te-topology-augment {
       description
         "Дополнение топологии TE.";
       uses te-types:te-topology-identifier;
       container te {
         must '../te-topology-identifier/provider-id'
            + ' and ../te-topology-identifier/client-id'
            + ' and ../te-topology-identifier/topology-id';
         presence "Поддержка TE.";
         description
           "Указывает поддержку TE.";
         uses te-topology-config;
         uses geolocation-container;
       }
     }
     // Дополнение топологии TE.

     grouping te-topology-config {
       description
         "Группировка конфигурации топологии TE.";
       leaf name {
         type string;
         description
           "Имя топологии TE. Атрибут не обязателен и может указываться
            оператором для описания топологии TE, полезного, когда 
            network-id (RFC 8345) не является описательным и не можеет
            изменяться, поскольку генерируется системой.";
         reference
           "RFC 8345: A YANG Data Model for Network Topologies";
       }
       leaf preference {
         type uint8 {
           range "1..255";
         }
         description
           "Предпочтение для этой топологии. Меньшее значение более
            предпочтительно.";
       }
       leaf optimization-criterion {
         type identityref {
           base te-types:objective-function-type;
         }
         description
           "Критерии оптимизации, применяемые к топологии.";
         reference
           "RFC 3272: Overview and Principles of Internet Traffic
            Engineering";
       }
       list nsrlg {
         if-feature "nsrlg";
         key "id";
         description
           "Список NSRLG (Non-Shared Risk Link Group).";
         reference
           "RFC 4872: RSVP-TE Extensions in Support of End-to-End
            Generalized Multi-Protocol Label Switching (GMPLS)
            Recovery";
         leaf id {
           type uint32;
           description
             "Указывает запись NSRLG.";
         }
         leaf disjointness {
           type te-types:te-path-disjointness;
           description
             "Тип разделения ресурсов.";
         }
       }
       // NSRLG
     }
     // Конфигурация топологии TE

     grouping template-attributes {
       description
         "Общие для всех шаблонов атрибуты.";
       leaf priority {
         type uint16;
         description
           "Уровень предпочтения для разрешения конфликтов между
            шаблонами. Когда значения атрибута заданы в нескольких
            шаблонах, используется значение из шаблона с высшим
            приоритетом. Меньшее значение указывает более высокий
            приоритет (наивысший 0).";
       }
       leaf reference-change-policy {
         type enumeration {
           enum no-action {
             description
               "При смене атрибута в этом шаблоне узел конфигурации
                со ссылкой на этот шаблон не выполняет действий.";
           }
           enum not-allowed {
             description
               "Когда объект конфигурации имеет ссылку на этот шаблон,
                менять шаблон не разрешается.";
           }
           enum cascade {
             description
               "При смене атрибута в этом шаблоне объект конфигурации,
                ссылающийся на шаблон, применяет новое значение 
                атрибута к соответствующей конфигурации.";
           }
         }
         description
           "Этот атрибут задаёт действие, применяемое к узлу
            конфигурации со ссылкой на этот шаблон.";
       }
     }
     // Атрибуты шаблона

     /*
      * Узлы данных
      */

     augment "/nw:networks/nw:network/nw:network-types" {
       description
         "Вносит новый тип сети для топологии TE.";
       container te-topology {
         presence "Указывает топологию TE.";
         description
           "Присутствие указывает тип топологии TE.";
       }
     }

     augment "/nw:networks" {
       description
         "Параметры дополнения для топологии TE.";
       uses te-topologies-augment;
     }

     augment "/nw:networks/nw:network" {
       when 'nw:network-types/tet:te-topology' {
         description
           "Параметры дополнения, применимые лишь для сетей с типом
            топологии TE.";
       }
       description
         "Параметры конфигурации для топологии TE.";
       uses te-topology-augment;
     }

     augment "/nw:networks/nw:network/nw:node" {
       when '../nw:network-types/tet:te-topology' {
         description
           "Параметры дополнения, применимые лишь для сетей с типом
            топологии TE.";
       }
       description
         "Параметры конфигурации для TE на уровне узла.";
       leaf te-node-id {
         type te-types:te-node-id;
         description
           "Идентификатор узла в топологии TE. Узел специфичен для
            топологии, к которой он относится.";
       }
       container te {
         must '../te-node-id' {
           description
             "te-node-id является обязательным.";
         }
         must 'count(../nw:supporting-node)<=1' {
           description
             "Для узла в топологии TE не может быть более одного
              поддерживающего узла. При абстрагировании нескольких узлов
              используется поле underlay-topology.";
         }
         presence "TE support";
         description
           "Указывает поддержку TE.";
         uses te-node-augment;
       }
     }

     augment "/nw:networks/nw:network/nt:link" {
       when '../nw:network-types/tet:te-topology' {
         description
           "Параметры дополнения, применимые лишь для сетей с типом
            топологии TE.";
       }
       description
         "Параметры конфигурации для TE на уровне канала.";
       container te {
         must 'count(../nt:supporting-link)<=1' {
           description
             "Для канала в топологии TE не может быть более одного
              поддерживающего канала. При абстрагировании нескольких 
              каналов используется базовый.";
         }
         presence "Поддержка TE.";
         description
           "Указывает поддержку TE.";
         uses te-link-augment;
       }
     }

     augment "/nw:networks/nw:network/nw:node/"
           + "nt:termination-point" {
       when '../../nw:network-types/tet:te-topology' {
         description
           "Параметры дополнения, применимые лишь для сетей с типом
            топологии TE.";
       }
       description
         "Cпараметры конфигурации для TE на уровне точки завершения.";
       uses te-termination-point-augment;
     }

     augment "/nw:networks/nw:network/nt:link/te/bundle-stack-level/"
           + "bundle/bundled-links/bundled-link" {
       when '../../../../nw:network-types/tet:te-topology' {
         description
           "Параметры дополнения, применимые лишь для сетей с типом
            топологии TE.";
       }
       description
         "Дополнение для канала-связки TE.";
       leaf src-tp-ref {
         type leafref {
           path "../../../../../nw:node[nw:node-id = "
              + "current()/../../../../nt:source/"
              + "nt:source-node]/"
              + "nt:termination-point/nt:tp-id";
           require-instance true;
         }
         description
           "Ссылка на другую точку завершения TE на том же 
            узле-источнике.";
       }
       leaf des-tp-ref {
         type leafref {
           path "../../../../../nw:node[nw:node-id = "
              + "current()/../../../../nt:destination/"
              + "nt:dest-node]/"
              + "nt:termination-point/nt:tp-id";
           require-instance true;
         }
         description
           "Указывает точку завершение TE на том же целевом узле.";
       }
     }

     augment "/nw:networks/nw:network/nw:node/te/"
           + "information-source-entry/connectivity-matrices/"
           + "connectivity-matrix" {
       when '../../../../../nw:network-types/tet:te-topology' {
         description
           "Параметры дополнения, применимые лишь для сетей с типом
            топологии TE.";
       }
       description
         "Дополнение для матрицы связности узла TE.";
       uses te-node-connectivity-matrix-attributes;
     }

     augment "/nw:networks/nw:network/nw:node/te/te-node-attributes/"
           + "connectivity-matrices/connectivity-matrix" {
       when '../../../../../nw:network-types/tet:te-topology' {
         description
           "Параметры дополнения, применимые лишь для сетей с типом
            топологии TE.";
       }
       description
         "Дополнение для матрицы связности узла TE.";
       uses te-node-connectivity-matrix-attributes;
     }

     augment "/nw:networks/nw:network/nw:node/te/"
           + "tunnel-termination-point/local-link-connectivities" {
       when '../../../../nw:network-types/tet:te-topology' {
         description
           "Параметры дополнения, применимые лишь для сетей с типом
            топологии TE.";
       }
       description
         "Дополнение для TTP LLC узла TE.";
       uses te-node-tunnel-termination-point-llc-list;
     }
   }
   <CODE ENDS>

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

Заданный этим документом модуль YANG определяет схему для данных, предназначенную для доступа через сеть с использованием протоколов управления, таких как NETCONF [RFC6241] или RESTCONF [RFC8040]. Нижним уровнем NETCONF служит защищённый транспорт с обязательной поддержкой SSH (Secure Shell) [RFC6242]. Нижним уровнем RESTCONF служит протокол HTTPS с обязательной поддержкой защиты на транспортном уровне (TLS) [RFC8446].

Модель доступа к конфигурации сети (NACM – Network Configuration Access Control Model) [RFC8341] обеспечивает возможность разрешить доступ лишь определённых пользователей NETCONF или RESTCONF к заранее заданному подмножеству операций NETCONF или RESTCONF и содержимого.

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

/nw:networks/nw:network/nw:network-types/tet:te-topology

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

/nw:networks/tet:te

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

/nw:networks/nw:network

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

/nw:networks/nw:network/nw:node

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

/nw:networks/nw:network/nt:link/tet:te

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

/nw:networks/nw:network/nw:node/nt:termination-point

Эта ветвь задаёт конфигурации TE LTP. Изменение конфигурации в этой ветви может добавлять, удалять или изменять TE LTP. Добавляя TE LTP, злоумышленник может создать несанкционированный путь для трафика, а удаляя или изменяя TE LTP, может отключить или отправить по ложному маршруту трафик на заданной точке TE LTP. Изменения трафика могут влиять на трафик в поддерживающих узлах TE и каналах TE этой топологии TE и связанных топологий TE.

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

/nw:networks/nw:network/nw:network-types/tet:te-topology

Несанкционированный доступ к этой ветви может раскрывать тип топологии TE.

/nw:networks/tet:te

Несанкционированный доступ к этой ветви может раскрывать шаблоны узлов и каналов TE.

/nw:networks/nw:network

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

/nw:networks/nw:network/nw:node

Несанкционированный доступ к этой ветви может раскрывать сведения о рабочем состоянии узлов TE.

/nw:networks/nw:network/nt:link/tet:te

Несанкционированный доступ к этой ветви может раскрывать сведения о рабочем состоянии каналов TE.

/nw:networks/nw:network/nw:node/nt:termination-point

Несанкционированный доступ к этой ветви может раскрывать сведения о рабочем состоянии точек TE LTP.

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

Агентство IANA зарегистрировало приведённые ниже URI в субреестре ns реестра IETF XML [RFC3688].

   URI:  urn:ietf:params:xml:ns:yang:ietf-te-topology
   Registrant Contact:  The IESG.
   XML:  N/A; the requested URI is an XML namespace.

   URI:  urn:ietf:params:xml:ns:yang:ietf-te-topology-state
   Registrant Contact:  The IESG.
   XML:  N/A; the requested URI is an XML namespace.

   IANA has registered the following YANG modules in the "YANG Module
   Names" subregistry [RFC6020] within the "YANG Parameters" registry.

   Name:  ietf-te-topology
   Namespace:  urn:ietf:params:xml:ns:yang:ietf-te-topology
   Prefix:  tet
   Reference:  RFC 8795

   Name:  ietf-te-topology-state
   Namespace:  urn:ietf:params:xml:ns:yang:ietf-te-topology-state
   Prefix:  tet-s
   Reference:  RFC 8795

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>.

[RFC3688] Mealling, M., «The IETF XML Registry», BCP 81, RFC 3688, DOI 10.17487/RFC3688, January 2004, <https://www.rfc-editor.org/info/rfc3688>.

[RFC3945] Mannie, E., Ed., «Generalized Multi-Protocol Label Switching (GMPLS) Architecture», RFC 3945, DOI 10.17487/RFC3945, October 2004, <https://www.rfc-editor.org/info/rfc3945>.

[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>.

[RFC7926] Farrel, A., Ed., Drake, J., Bitar, N., Swallow, G., Ceccarelli, D., and X. Zhang, «Problem Statement and Architecture for Information Exchange between Interconnected Traffic-Engineered Networks», BCP 206, RFC 7926, DOI 10.17487/RFC7926, July 2016, <https://www.rfc-editor.org/info/rfc7926>.

[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>.

[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>.

[RFC8446] Rescorla, E., «The Transport Layer Security (TLS) Protocol Version 1.3», RFC 8446, DOI 10.17487/RFC8446, August 2018, <https://www.rfc-editor.org/info/rfc8446>.

[RFC8776] Saad, T., Gandhi, R., Liu, X., Beeram, V., and I. Bryskin, «Common YANG Data Types for Traffic Engineering», RFC 8776, DOI 10.17487/RFC8776, June 2020, <https://www.rfc-editor.org/info/rfc8776>.

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

[G.709] ITU-T, «Interfaces for the optical transport network», ITU-T Recommendation G.709, June 2020, <https://www.itu.int/rec/T-REC-G.709/>.

[G.805] ITU-T, «Generic functional architecture of transport networks», ITU-T Recommendation G.805, March 2000, <https://www.itu.int/rec/T-REC-G.805/en>.

[G.8080] ITU-T, «Architecture for the automatically switched optical network», ITU-T Recommendation G.8080, February 2012, <https://www.itu.int/rec/T-REC-G.8080/en>.

[G.872] ITU-T, «Architecture of optical transport networks», ITU-T Recommendation G.872, December 2019, <https://www.itu.int/rec/T-REC-G.872/en>.

[RFC1195] Callon, R., «Use of OSI IS-IS for routing in TCP/IP and dual environments», RFC 1195, DOI 10.17487/RFC1195, December 1990, <https://www.rfc-editor.org/info/rfc1195>.

[RFC2702] Awduche, D., Malcolm, J., Agogbua, J., O’Dell, M., and J. McManus, «Requirements for Traffic Engineering Over MPLS», RFC 2702, DOI 10.17487/RFC2702, September 1999, <https://www.rfc-editor.org/info/rfc2702>.

[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>.

[RFC3272] Awduche, D., Chiu, A., Elwalid, A., Widjaja, I., and X. Xiao, «Overview and Principles of Internet Traffic Engineering», RFC 3272, DOI 10.17487/RFC3272, May 2002, <https://www.rfc-editor.org/info/rfc3272>.

[RFC3471] Berger, L., Ed., «Generalized Multi-Protocol Label Switching (GMPLS) Signaling Functional Description», RFC 3471, DOI 10.17487/RFC3471, January 2003, <https://www.rfc-editor.org/info/rfc3471>.

[RFC3630] Katz, D., Kompella, K., and D. Yeung, «Traffic Engineering (TE) Extensions to OSPF Version 2», RFC 3630, DOI 10.17487/RFC3630, September 2003, <https://www.rfc-editor.org/info/rfc3630>.

[RFC3785] Le Faucheur, F., Uppili, R., Vedrenne, A., Merckx, P., and T. Telkamp, «Use of Interior Gateway Protocol (IGP) Metric as a second MPLS Traffic Engineering (TE) Metric», BCP 87, RFC 3785, DOI 10.17487/RFC3785, May 2004, <https://www.rfc-editor.org/info/rfc3785>.

[RFC4201] Kompella, K., Rekhter, Y., and L. Berger, «Link Bundling in MPLS Traffic Engineering (TE)», RFC 4201, DOI 10.17487/RFC4201, October 2005, <https://www.rfc-editor.org/info/rfc4201>.

[RFC4202] Kompella, K., Ed. and Y. Rekhter, Ed., «Routing Extensions in Support of Generalized Multi-Protocol Label Switching (GMPLS)», RFC 4202, DOI 10.17487/RFC4202, October 2005, <https://www.rfc-editor.org/info/rfc4202>.

[RFC4203] Kompella, K., Ed. and Y. Rekhter, Ed., «OSPF Extensions in Support of Generalized Multi-Protocol Label Switching (GMPLS)», RFC 4203, DOI 10.17487/RFC4203, October 2005, <https://www.rfc-editor.org/info/rfc4203>.

[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>.

[RFC4872] Lang, J.P., Ed., Rekhter, Y., Ed., and D. Papadimitriou, Ed., «RSVP-TE Extensions in Support of End-to-End Generalized Multi-Protocol Label Switching (GMPLS) Recovery», RFC 4872, DOI 10.17487/RFC4872, May 2007, <https://www.rfc-editor.org/info/rfc4872>.

[RFC5152] Vasseur, JP., Ed., Ayyangar, A., Ed., and R. Zhang, «A Per-Domain Path Computation Method for Establishing Inter-Domain Traffic Engineering (TE) Label Switched Paths (LSPs)», RFC 5152, DOI 10.17487/RFC5152, February 2008, <https://www.rfc-editor.org/info/rfc5152>.

[RFC5212] Shiomoto, K., Papadimitriou, D., Le Roux, JL., Vigoureux, M., and D. Brungard, «Requirements for GMPLS-Based Multi-Region and Multi-Layer Networks (MRN/MLN)», RFC 5212, DOI 10.17487/RFC5212, July 2008, <https://www.rfc-editor.org/info/rfc5212>.

[RFC5305] Li, T. and H. Smit, «IS-IS Extensions for Traffic Engineering», RFC 5305, DOI 10.17487/RFC5305, October 2008, <https://www.rfc-editor.org/info/rfc5305>.

[RFC5316] Chen, M., Zhang, R., and X. Duan, «ISIS Extensions in Support of Inter-Autonomous System (AS) MPLS and GMPLS Traffic Engineering», RFC 5316, DOI 10.17487/RFC5316, December 2008, <https://www.rfc-editor.org/info/rfc5316>.

[RFC5392] Chen, M., Zhang, R., and X. Duan, «OSPF Extensions in Support of Inter-Autonomous System (AS) MPLS and GMPLS Traffic Engineering», RFC 5392, DOI 10.17487/RFC5392, January 2009, <https://www.rfc-editor.org/info/rfc5392>.

[RFC6001] Papadimitriou, D., Vigoureux, M., Shiomoto, K., Brungard, D., and JL. Le Roux, «Generalized MPLS (GMPLS) Protocol Extensions for Multi-Layer and Multi-Region Networks (MLN/MRN)», RFC 6001, DOI 10.17487/RFC6001, October 2010, <https://www.rfc-editor.org/info/rfc6001>.

[RFC7308] Osborne, E., «Extended Administrative Groups in MPLS Traffic Engineering (MPLS-TE)», RFC 7308, DOI 10.17487/RFC7308, July 2014, <https://www.rfc-editor.org/info/rfc7308>.

[RFC7471] Giacalone, S., Ward, D., Drake, J., Atlas, A., and S. Previdi, «OSPF Traffic Engineering (TE) Metric Extensions», RFC 7471, DOI 10.17487/RFC7471, March 2015, <https://www.rfc-editor.org/info/rfc7471>.

[RFC7579] Bernstein, G., Ed., Lee, Y., Ed., Li, D., Imajuku, W., and J. Han, «General Network Element Constraint Encoding for GMPLS-Controlled Networks», RFC 7579, DOI 10.17487/RFC7579, June 2015, <https://www.rfc-editor.org/info/rfc7579>.

[RFC7752] Gredler, H., Ed., Medved, J., Previdi, S., Farrel, A., and S. Ray, «North-Bound Distribution of Link-State and Traffic Engineering (TE) Information Using BGP», RFC 7752, DOI 10.17487/RFC7752, March 2016, <https://www.rfc-editor.org/info/rfc7752>.

[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>.

[RFC8639] Voit, E., Clemm, A., Gonzalez Prieto, A., Nilsen-Nygaard, E., and A. Tripathy, «Subscription to YANG Notifications», RFC 8639, DOI 10.17487/RFC8639, September 2019, <https://www.rfc-editor.org/info/rfc8639>.

[RFC8641] Clemm, A. and E. Voit, «Subscription to YANG Notifications for Datastore Updates», RFC 8641, DOI 10.17487/RFC8641, September 2019, <https://www.rfc-editor.org/info/rfc8641>.

[TEAS-TOPO] Bryskin, I., Beeram, V., Saad, T., and X. Liu, «TE Topology and Tunnel Modeling for Transport Networks», Work in Progress, Internet-Draft, draft-ietf-teas-te-topo-and-tunnel-modeling-06, 12 July 2020, <https://tools.ietf.org/html/draft-ietf-teas-te-topo-and-tunnel-modeling-06>.

[YANG-CFG-SCHED] Liu, X., Bryskin, I., Beeram, V., Saad, T., Shah, H., and O. Gonzalez de Dios, «A YANG Data Model for Configuration Scheduling», Work in Progress, Internet-Draft, draft-liu-netmod-yang-schedule-05, 1 March 2018, <https://tools.ietf.org/html/draft-liu-netmod-yang-schedule-05>.

[YANG-L3] Liu, X., Bryskin, I., Beeram, V., Saad, T., Shah, H., and O. Gonzalez de Dios, «YANG Data Model for Layer 3 TE Topologies», Work in Progress, Internet-Draft, draft-ietf-teas-yang-l3-te-topo-08, 12 July 2020, <https://tools.ietf.org/html/draft-ietf-teas-yang-l3-te-topo-08>.

[YANG-OTN] Zheng, H., Busi, I., Liu, X., Belotti, S., and O. Gonzalez de Dios, «A YANG Data Model for Optical Transport Network Topology», Work in Progress, Internet-Draft, draft-ietf-ccamp-otn-topo-yang-10, 9 March 2020, <https://tools.ietf.org/html/draft-ietf-ccamp-otn-topo-yang-10>.

[YANG-WSON] Zheng, H., Lee, Y., Guo, A., Lopez, V., and D. King, «A YANG Data Model for WSON (Wavelength Switched Optical Networks)», Work in Progress7, Internet-Draft, draft-ietf-ccamp-wson-yang-25, 19 May 2020, <https://tools.ietf.org/html/draft-ietf-ccamp-wson-yang-25>.

Приложение A. Полное дерево модели

   module: ietf-te-topology
     augment /nw:networks/nw:network/nw:network-types:
       +--rw te-topology!
     augment /nw:networks:
       +--rw te!
          +--rw templates
             +--rw node-template* [name] {template}?
             |  +--rw name
             |  |       te-types:te-template-name
             |  +--rw priority?                  uint16
             |  +--rw reference-change-policy?   enumeration
             |  +--rw te-node-attributes
             |     +--rw admin-status?        te-types:te-admin-status
             |     +--rw domain-id?           uint32
             |     +--rw is-abstract?         empty
             |     +--rw name?                string
             |     +--rw signaling-address*   inet:ip-address
             |     +--rw underlay-topology {te-topology-hierarchy}?
             |        +--rw network-ref?
             |                -> /nw:networks/network/network-id
             +--rw link-template* [name] {template}?
                +--rw name
                |       te-types:te-template-name
                +--rw priority?                  uint16
                +--rw reference-change-policy?   enumeration
                +--rw te-link-attributes
                   +--rw access-type?
                   |       te-types:te-link-access-type
                   +--rw external-domain
                   |  +--rw network-ref?
                   |  |       -> /nw:networks/network/network-id
                   |  +--rw remote-te-node-id?      te-types:te-node-id
                   |  +--rw remote-te-link-tp-id?   te-types:te-tp-id
                   +--rw is-abstract?                      empty
                   +--rw name?                             string
                   +--rw underlay {te-topology-hierarchy}?
                   |  +--rw enabled?                     boolean
                   |  +--rw primary-path
                   |  |  +--rw network-ref?
                   |  |  |       -> /nw:networks/network/network-id
                   |  |  +--rw path-element* [path-element-id]
                   |  |     +--rw path-element-id              uint32
                   |  |     +--rw (type)?
                   |  |        +--:(numbered-node-hop)
                   |  |        |  +--rw numbered-node-hop
                   |  |        |     +--rw node-id     te-node-id
                   |  |        |     +--rw hop-type?   te-hop-type
                   |  |        +--:(numbered-link-hop)
                   |  |        |  +--rw numbered-link-hop
                   |  |        |     +--rw link-tp-id    te-tp-id
                   |  |        |     +--rw hop-type?     te-hop-type
                   |  |        |     +--rw direction?
                   |  |        |             te-link-direction
                   |  |        +--:(unnumbered-link-hop)
                   |  |        |  +--rw unnumbered-link-hop
                   |  |        |     +--rw link-tp-id    te-tp-id
                   |  |        |     +--rw node-id       te-node-id
                   |  |        |     +--rw hop-type?     te-hop-type
                   |  |        |     +--rw direction?
                   |  |        |             te-link-direction
                   |  |        +--:(as-number)
                   |  |        |  +--rw as-number-hop
                   |  |        |     +--rw as-number    inet:as-number
                   |  |        |     +--rw hop-type?    te-hop-type
                   |  |        +--:(label)
                   |  |           +--rw label-hop
                   |  |              +--rw te-label
                   |  |                 +--rw (technology)?
                   |  |                 |  +--:(generic)
                   |  |                 |     +--rw generic?
                   |  |                 |             rt-types:generalized-label
                   |  |                 +--rw direction?
                   |  |                         te-label-direction
                   |  +--rw backup-path* [index]
                   |  |  +--rw index           uint32
                   |  |  +--rw network-ref?
                   |  |  |       -> /nw:networks/network/network-id
                   |  |  +--rw path-element* [path-element-id]
                   |  |     +--rw path-element-id              uint32
                   |  |     +--rw (type)?
                   |  |        +--:(numbered-node-hop)
                   |  |        |  +--rw numbered-node-hop
                   |  |        |     +--rw node-id     te-node-id
                   |  |        |     +--rw hop-type?   te-hop-type
                   |  |        +--:(numbered-link-hop)
                   |  |        |  +--rw numbered-link-hop
                   |  |        |     +--rw link-tp-id    te-tp-id
                   |  |        |     +--rw hop-type?     te-hop-type
                   |  |        |     +--rw direction?
                   |  |        |             te-link-direction
                   |  |        +--:(unnumbered-link-hop)
                   |  |        |  +--rw unnumbered-link-hop
                   |  |        |     +--rw link-tp-id    te-tp-id
                   |  |        |     +--rw node-id       te-node-id
                   |  |        |     +--rw hop-type?     te-hop-type
                   |  |        |     +--rw direction?
                   |  |        |             te-link-direction
                   |  |        +--:(as-number)
                   |  |        |  +--rw as-number-hop
                   |  |        |     +--rw as-number    inet:as-number
                   |  |        |     +--rw hop-type?    te-hop-type
                   |  |        +--:(label)
                   |  |           +--rw label-hop
                   |  |              +--rw te-label
                   |  |                 +--rw (technology)?
                   |  |                 |  +--:(generic)
                   |  |                 |     +--rw generic?
                   |  |                 |             rt-types:generalized-label
                   |  |                 +--rw direction?
                   |  |                         te-label-direction
                   |  +--rw protection-type?             identityref
                   |  +--rw tunnel-termination-points
                   |  |  +--rw source?        binary
                   |  |  +--rw destination?   binary
                   |  +--rw tunnels
                   |     +--rw sharing?   boolean
                   |     +--rw tunnel* [tunnel-name]
                   |        +--rw tunnel-name    string
                   |        +--rw sharing?       boolean
                   +--rw admin-status?
                   |       te-types:te-admin-status
                   +--rw link-index?                       uint64
                   +--rw administrative-group?
                   |       te-types:admin-groups
                   +--rw interface-switching-capability*
                   |       [switching-capability encoding]
                   |  +--rw switching-capability    identityref
                   |  +--rw encoding                identityref
                   |  +--rw max-lsp-bandwidth* [priority]
                   |     +--rw priority        uint8
                   |     +--rw te-bandwidth
                   |        +--rw (technology)?
                   |           +--:(generic)
                   |              +--rw generic?   te-bandwidth
                   +--rw label-restrictions
                   |  +--rw label-restriction* [index]
                   |     +--rw restriction?    enumeration
                   |     +--rw index           uint32
                   |     +--rw label-start
                   |     |  +--rw te-label
                   |     |     +--rw (technology)?
                   |     |     |  +--:(generic)
                   |     |     |     +--rw generic?
                   |     |     |             rt-types:generalized-label
                   |     |     +--rw direction?       te-label-direction
                   |     +--rw label-end
                   |     |  +--rw te-label
                   |     |     +--rw (technology)?
                   |     |     |  +--:(generic)
                   |     |     |     +--rw generic?
                   |     |     |             rt-types:generalized-label
                   |     |     +--rw direction?       te-label-direction
                   |     +--rw label-step
                   |     |  +--rw (technology)?
                   |     |     +--:(generic)
                   |     |        +--rw generic?   int32
                   |     +--rw range-bitmap?   yang:hex-string
                   +--rw link-protection-type?             identityref
                   +--rw max-link-bandwidth
                   |  +--rw te-bandwidth
                   |     +--rw (technology)?
                   |        +--:(generic)
                   |           +--rw generic?   te-bandwidth
                   +--rw max-resv-link-bandwidth
                   |  +--rw te-bandwidth
                   |     +--rw (technology)?
                   |        +--:(generic)
                   |           +--rw generic?   te-bandwidth
                   +--rw unreserved-bandwidth* [priority]
                   |  +--rw priority        uint8
                   |  +--rw te-bandwidth
                   |     +--rw (technology)?
                   |        +--:(generic)
                   |           +--rw generic?   te-bandwidth
                   +--rw te-default-metric?                uint32
                   +--rw te-delay-metric?                  uint32
                   +--rw te-igp-metric?                    uint32
                   +--rw te-srlgs
                   |  +--rw value*   te-types:srlg
                   +--rw te-nsrlgs {nsrlg}?
                      +--rw id*   uint32
     augment /nw:networks/nw:network:
       +--rw te-topology-identifier
       |  +--rw provider-id?   te-global-id
       |  +--rw client-id?     te-global-id
       |  +--rw topology-id?   te-topology-id
       +--rw te!
          +--rw name?                     string
          +--rw preference?               uint8
          +--rw optimization-criterion?   identityref
          +--rw nsrlg* [id] {nsrlg}?
          |  +--rw id              uint32
          |  +--rw disjointness?   te-types:te-path-disjointness
          +--ro geolocation
             +--ro altitude?    int64
             +--ro latitude?    geographic-coordinate-degree
             +--ro longitude?   geographic-coordinate-degree
     augment /nw:networks/nw:network/nw:node:
       +--rw te-node-id?   te-types:te-node-id
       +--rw te!
          +--rw te-node-template*
          |       -> ../../../../te/templates/node-template/name
          |       {template}?
          +--rw te-node-attributes
          |  +--rw admin-status?            te-types:te-admin-status
          |  +--rw connectivity-matrices
          |  |  +--rw number-of-entries?     uint16
          |  |  +--rw label-restrictions
          |  |  |  +--rw label-restriction* [index]
          |  |  |     +--rw restriction?    enumeration
          |  |  |     +--rw index           uint32
          |  |  |     +--rw label-start
          |  |  |     |  +--rw te-label
          |  |  |     |     +--rw (technology)?
          |  |  |     |     |  +--:(generic)
          |  |  |     |     |     +--rw generic?
          |  |  |     |     |             rt-types:generalized-label
          |  |  |     |     +--rw direction?       te-label-direction
          |  |  |     +--rw label-end
          |  |  |     |  +--rw te-label
          |  |  |     |     +--rw (technology)?
          |  |  |     |     |  +--:(generic)
          |  |  |     |     |     +--rw generic?
          |  |  |     |     |             rt-types:generalized-label
          |  |  |     |     +--rw direction?       te-label-direction
          |  |  |     +--rw label-step
          |  |  |     |  +--rw (technology)?
          |  |  |     |     +--:(generic)
          |  |  |     |        +--rw generic?   int32
          |  |  |     +--rw range-bitmap?   yang:hex-string
          |  |  +--rw is-allowed?            boolean
          |  |  +--rw underlay {te-topology-hierarchy}?
          |  |  |  +--rw enabled?                     boolean
          |  |  |  +--rw primary-path
          |  |  |  |  +--rw network-ref?
          |  |  |  |  |       -> /nw:networks/network/network-id
          |  |  |  |  +--rw path-element* [path-element-id]
          |  |  |  |     +--rw path-element-id              uint32
          |  |  |  |     +--rw (type)?
          |  |  |  |        +--:(numbered-node-hop)
          |  |  |  |        |  +--rw numbered-node-hop
          |  |  |  |        |     +--rw node-id     te-node-id
          |  |  |  |        |     +--rw hop-type?   te-hop-type
          |  |  |  |        +--:(numbered-link-hop)
          |  |  |  |        |  +--rw numbered-link-hop
          |  |  |  |        |     +--rw link-tp-id    te-tp-id
          |  |  |  |        |     +--rw hop-type?     te-hop-type
          |  |  |  |        |     +--rw direction?    te-link-direction
          |  |  |  |        +--:(unnumbered-link-hop)
          |  |  |  |        |  +--rw unnumbered-link-hop
          |  |  |  |        |     +--rw link-tp-id    te-tp-id
          |  |  |  |        |     +--rw node-id       te-node-id
          |  |  |  |        |     +--rw hop-type?     te-hop-type
          |  |  |  |        |     +--rw direction?    te-link-direction
          |  |  |  |        +--:(as-number)
          |  |  |  |        |  +--rw as-number-hop
          |  |  |  |        |     +--rw as-number    inet:as-number
          |  |  |  |        |     +--rw hop-type?    te-hop-type
          |  |  |  |        +--:(label)
          |  |  |  |           +--rw label-hop
          |  |  |  |              +--rw te-label
          |  |  |  |                 +--rw (technology)?
          |  |  |  |                 |  +--:(generic)
          |  |  |  |                 |     +--rw generic?
          |  |  |  |                 |             rt-types:generalized-label
          |  |  |  |                 +--rw direction?
          |  |  |  |                         te-label-direction
          |  |  |  +--rw backup-path* [index]
          |  |  |  |  +--rw index           uint32
          |  |  |  |  +--rw network-ref?
          |  |  |  |  |       -> /nw:networks/network/network-id
          |  |  |  |  +--rw path-element* [path-element-id]
          |  |  |  |     +--rw path-element-id              uint32
          |  |  |  |     +--rw (type)?
          |  |  |  |        +--:(numbered-node-hop)
          |  |  |  |        |  +--rw numbered-node-hop
          |  |  |  |        |     +--rw node-id     te-node-id
          |  |  |  |        |     +--rw hop-type?   te-hop-type
          |  |  |  |        +--:(numbered-link-hop)
          |  |  |  |        |  +--rw numbered-link-hop
          |  |  |  |        |     +--rw link-tp-id    te-tp-id
          |  |  |  |        |     +--rw hop-type?     te-hop-type
          |  |  |  |        |     +--rw direction?    te-link-direction
          |  |  |  |        +--:(unnumbered-link-hop)
          |  |  |  |        |  +--rw unnumbered-link-hop
          |  |  |  |        |     +--rw link-tp-id    te-tp-id
          |  |  |  |        |     +--rw node-id       te-node-id
          |  |  |  |        |     +--rw hop-type?     te-hop-type
          |  |  |  |        |     +--rw direction?    te-link-direction
          |  |  |  |        +--:(as-number)
          |  |  |  |        |  +--rw as-number-hop
          |  |  |  |        |     +--rw as-number    inet:as-number
          |  |  |  |        |     +--rw hop-type?    te-hop-type
          |  |  |  |        +--:(label)
          |  |  |  |           +--rw label-hop
          |  |  |  |              +--rw te-label
          |  |  |  |                 +--rw (technology)?
          |  |  |  |                 |  +--:(generic)
          |  |  |  |                 |     +--rw generic?
          |  |  |  |                 |             rt-types:generalized-label
          |  |  |  |                 +--rw direction?
          |  |  |  |                         te-label-direction
          |  |  |  +--rw protection-type?             identityref
          |  |  |  +--rw tunnel-termination-points
          |  |  |  |  +--rw source?        binary
          |  |  |  |  +--rw destination?   binary
          |  |  |  +--rw tunnels
          |  |  |     +--rw sharing?   boolean
          |  |  |     +--rw tunnel* [tunnel-name]
          |  |  |        +--rw tunnel-name    string
          |  |  |        +--rw sharing?       boolean
          |  |  +--rw path-constraints
          |  |  |  +--rw te-bandwidth
          |  |  |  |  +--rw (technology)?
          |  |  |  |     +--:(generic)
          |  |  |  |        +--rw generic?   te-bandwidth
          |  |  |  +--rw link-protection?          identityref
          |  |  |  +--rw setup-priority?           uint8
          |  |  |  +--rw hold-priority?            uint8
          |  |  |  +--rw signaling-type?           identityref
          |  |  |  +--rw path-metric-bounds
          |  |  |  |  +--rw path-metric-bound* [metric-type]
          |  |  |  |     +--rw metric-type    identityref
          |  |  |  |     +--rw upper-bound?   uint64
          |  |  |  +--rw path-affinities-values
          |  |  |  |  +--rw path-affinities-value* [usage]
          |  |  |  |     +--rw usage    identityref
          |  |  |  |     +--rw value?   admin-groups
          |  |  |  +--rw path-affinity-names
          |  |  |  |  +--rw path-affinity-name* [usage]
          |  |  |  |     +--rw usage            identityref
          |  |  |  |     +--rw affinity-name* [name]
          |  |  |  |        +--rw name    string
          |  |  |  +--rw path-srlgs-lists
          |  |  |  |  +--rw path-srlgs-list* [usage]
          |  |  |  |     +--rw usage     identityref
          |  |  |  |     +--rw values*   srlg
          |  |  |  +--rw path-srlgs-names
          |  |  |  |  +--rw path-srlgs-name* [usage]
          |  |  |  |     +--rw usage    identityref
          |  |  |  |     +--rw names*   string
          |  |  |  +--rw disjointness?             te-path-disjointness
          |  |  +--rw optimizations
          |  |  |  +--rw (algorithm)?
          |  |  |     +--:(metric) {path-optimization-metric}?
          |  |  |     |  +--rw optimization-metric* [metric-type]
          |  |  |     |  |  +--rw metric-type
          |  |  |     |  |  |       identityref
          |  |  |     |  |  +--rw weight?
          |  |  |     |  |  |       uint8
          |  |  |     |  |  +--rw explicit-route-exclude-objects
          |  |  |     |  |  |  +--rw route-object-exclude-object*
          |  |  |     |  |  |          [index]
          |  |  |     |  |  |     +--rw index
          |  |  |     |  |  |     |       uint32
          |  |  |     |  |  |     +--rw (type)?
          |  |  |     |  |  |        +--:(numbered-node-hop)
          |  |  |     |  |  |        |  +--rw numbered-node-hop
          |  |  |     |  |  |        |     +--rw node-id     te-node-id
          |  |  |     |  |  |        |     +--rw hop-type?   te-hop-type
          |  |  |     |  |  |        +--:(numbered-link-hop)
          |  |  |     |  |  |        |  +--rw numbered-link-hop
          |  |  |     |  |  |        |     +--rw link-tp-id    te-tp-id
          |  |  |     |  |  |        |     +--rw hop-type?
          |  |  |     |  |  |        |     |       te-hop-type
          |  |  |     |  |  |        |     +--rw direction?
          |  |  |     |  |  |        |             te-link-direction
          |  |  |     |  |  |        +--:(unnumbered-link-hop)
          |  |  |     |  |  |        |  +--rw unnumbered-link-hop
          |  |  |     |  |  |        |     +--rw link-tp-id    te-tp-id
          |  |  |     |  |  |        |     +--rw node-id
          |  |  |     |  |  |        |     |       te-node-id
          |  |  |     |  |  |        |     +--rw hop-type?
          |  |  |     |  |  |        |     |       te-hop-type
          |  |  |     |  |  |        |     +--rw direction?
          |  |  |     |  |  |        |             te-link-direction
          |  |  |     |  |  |        +--:(as-number)
          |  |  |     |  |  |        |  +--rw as-number-hop
          |  |  |     |  |  |        |     +--rw as-number
          |  |  |     |  |  |        |     |       inet:as-number
          |  |  |     |  |  |        |     +--rw hop-type?
          |  |  |     |  |  |        |             te-hop-type
          |  |  |     |  |  |        +--:(label)
          |  |  |     |  |  |        |  +--rw label-hop
          |  |  |     |  |  |        |     +--rw te-label
          |  |  |     |  |  |        |        +--rw (technology)?
          |  |  |     |  |  |        |        |  +--:(generic)
          |  |  |     |  |  |        |        |     +--rw generic?
          |  |  |     |  |  |        |        |             rt-types:generalized-label
          |  |  |     |  |  |        |        +--rw direction?
          |  |  |     |  |  |        |                te-label-direction
          |  |  |     |  |  |        +--:(srlg)
          |  |  |     |  |  |           +--rw srlg
          |  |  |     |  |  |              +--rw srlg?   uint32
          |  |  |     |  |  +--rw explicit-route-include-objects
          |  |  |     |  |     +--rw route-object-include-object*
          |  |  |     |  |             [index]
          |  |  |     |  |        +--rw index
          |  |  |     |  |        |       uint32
          |  |  |     |  |        +--rw (type)?
          |  |  |     |  |           +--:(numbered-node-hop)
          |  |  |     |  |           |  +--rw numbered-node-hop
          |  |  |     |  |           |     +--rw node-id     te-node-id
          |  |  |     |  |           |     +--rw hop-type?   te-hop-type
          |  |  |     |  |           +--:(numbered-link-hop)
          |  |  |     |  |           |  +--rw numbered-link-hop
          |  |  |     |  |           |     +--rw link-tp-id    te-tp-id
          |  |  |     |  |           |     +--rw hop-type?
          |  |  |     |  |           |     |       te-hop-type
          |  |  |     |  |           |     +--rw direction?
          |  |  |     |  |           |             te-link-direction
          |  |  |     |  |           +--:(unnumbered-link-hop)
          |  |  |     |  |           |  +--rw unnumbered-link-hop
          |  |  |     |  |           |     +--rw link-tp-id    te-tp-id
          |  |  |     |  |           |     +--rw node-id
          |  |  |     |  |           |     |       te-node-id
          |  |  |     |  |           |     +--rw hop-type?
          |  |  |     |  |           |     |       te-hop-type
          |  |  |     |  |           |     +--rw direction?
          |  |  |     |  |           |             te-link-direction
          |  |  |     |  |           +--:(as-number)
          |  |  |     |  |           |  +--rw as-number-hop
          |  |  |     |  |           |     +--rw as-number
          |  |  |     |  |           |     |       inet:as-number
          |  |  |     |  |           |     +--rw hop-type?
          |  |  |     |  |           |             te-hop-type
          |  |  |     |  |           +--:(label)
          |  |  |     |  |              +--rw label-hop
          |  |  |     |  |                 +--rw te-label
          |  |  |     |  |                    +--rw (technology)?
          |  |  |     |  |                    |  +--:(generic)
          |  |  |     |  |                    |     +--rw generic?
          |  |  |     |  |                    |             rt-types:generalized-label
          |  |  |     |  |                    +--rw direction?
          |  |  |     |  |                            te-label-direction
          |  |  |     |  +--rw tiebreakers
          |  |  |     |     +--rw tiebreaker* [tiebreaker-type]
          |  |  |     |        +--rw tiebreaker-type    identityref
          |  |  |     +--:(objective-function)
          |  |  |              {path-optimization-objective-function}?
          |  |  |        +--rw objective-function
          |  |  |           +--rw objective-function-type?   identityref
          |  |  +--ro path-properties
          |  |  |  +--ro path-metric* [metric-type]
          |  |  |  |  +--ro metric-type           identityref
          |  |  |  |  +--ro accumulative-value?   uint64
          |  |  |  +--ro path-affinities-values
          |  |  |  |  +--ro path-affinities-value* [usage]
          |  |  |  |     +--ro usage    identityref
          |  |  |  |     +--ro value?   admin-groups
          |  |  |  +--ro path-affinity-names
          |  |  |  |  +--ro path-affinity-name* [usage]
          |  |  |  |     +--ro usage            identityref
          |  |  |  |     +--ro affinity-name* [name]
          |  |  |  |        +--ro name    string
          |  |  |  +--ro path-srlgs-lists
          |  |  |  |  +--ro path-srlgs-list* [usage]
          |  |  |  |     +--ro usage     identityref
          |  |  |  |     +--ro values*   srlg
          |  |  |  +--ro path-srlgs-names
          |  |  |  |  +--ro path-srlgs-name* [usage]
          |  |  |  |     +--ro usage    identityref
          |  |  |  |     +--ro names*   string
          |  |  |  +--ro path-route-objects
          |  |  |     +--ro path-route-object* [index]
          |  |  |        +--ro index                        uint32
          |  |  |        +--ro (type)?
          |  |  |           +--:(numbered-node-hop)
          |  |  |           |  +--ro numbered-node-hop
          |  |  |           |     +--ro node-id     te-node-id
          |  |  |           |     +--ro hop-type?   te-hop-type
          |  |  |           +--:(numbered-link-hop)
          |  |  |           |  +--ro numbered-link-hop
          |  |  |           |     +--ro link-tp-id    te-tp-id
          |  |  |           |     +--ro hop-type?     te-hop-type
          |  |  |           |     +--ro direction?    te-link-direction
          |  |  |           +--:(unnumbered-link-hop)
          |  |  |           |  +--ro unnumbered-link-hop
          |  |  |           |     +--ro link-tp-id    te-tp-id
          |  |  |           |     +--ro node-id       te-node-id
          |  |  |           |     +--ro hop-type?     te-hop-type
          |  |  |           |     +--ro direction?    te-link-direction
          |  |  |           +--:(as-number)
          |  |  |           |  +--ro as-number-hop
          |  |  |           |     +--ro as-number    inet:as-number
          |  |  |           |     +--ro hop-type?    te-hop-type
          |  |  |           +--:(label)
          |  |  |              +--ro label-hop
          |  |  |                 +--ro te-label
          |  |  |                    +--ro (technology)?
          |  |  |                    |  +--:(generic)
          |  |  |                    |     +--ro generic?
          |  |  |                    |             rt-types:generalized-label
          |  |  |                    +--ro direction?
          |  |  |                            te-label-direction
          |  |  +--rw connectivity-matrix* [id]
          |  |     +--rw id                  uint32
          |  |     +--rw from
          |  |     |  +--rw tp-ref?               leafref
          |  |     |  +--rw label-restrictions
          |  |     |     +--rw label-restriction* [index]
          |  |     |        +--rw restriction?    enumeration
          |  |     |        +--rw index           uint32
          |  |     |        +--rw label-start
          |  |     |        |  +--rw te-label
          |  |     |        |     +--rw (technology)?
          |  |     |        |     |  +--:(generic)
          |  |     |        |     |     +--rw generic?
          |  |     |        |     |             rt-types:generalized-label
          |  |     |        |     +--rw direction?
          |  |     |        |             te-label-direction
          |  |     |        +--rw label-end
          |  |     |        |  +--rw te-label
          |  |     |        |     +--rw (technology)?
          |  |     |        |     |  +--:(generic)
          |  |     |        |     |     +--rw generic?
          |  |     |        |     |             rt-types:generalized-label
          |  |     |        |     +--rw direction?
          |  |     |        |             te-label-direction
          |  |     |        +--rw label-step
          |  |     |        |  +--rw (technology)?
          |  |     |        |     +--:(generic)
          |  |     |        |        +--rw generic?   int32
          |  |     |        +--rw range-bitmap?   yang:hex-string
          |  |     +--rw to
          |  |     |  +--rw tp-ref?               leafref
          |  |     |  +--rw label-restrictions
          |  |     |     +--rw label-restriction* [index]
          |  |     |        +--rw restriction?    enumeration
          |  |     |        +--rw index           uint32
          |  |     |        +--rw label-start
          |  |     |        |  +--rw te-label
          |  |     |        |     +--rw (technology)?
          |  |     |        |     |  +--:(generic)
          |  |     |        |     |     +--rw generic?
          |  |     |        |     |             rt-types:generalized-label
          |  |     |        |     +--rw direction?
          |  |     |        |             te-label-direction
          |  |     |        +--rw label-end
          |  |     |        |  +--rw te-label
          |  |     |        |     +--rw (technology)?
          |  |     |        |     |  +--:(generic)
          |  |     |        |     |     +--rw generic?
          |  |     |        |     |             rt-types:generalized-label
          |  |     |        |     +--rw direction?
          |  |     |        |             te-label-direction
          |  |     |        +--rw label-step
          |  |     |        |  +--rw (technology)?
          |  |     |        |     +--:(generic)
          |  |     |        |        +--rw generic?   int32
          |  |     |        +--rw range-bitmap?   yang:hex-string
          |  |     +--rw is-allowed?         boolean
          |  |     +--rw underlay {te-topology-hierarchy}?
          |  |     |  +--rw enabled?                     boolean
          |  |     |  +--rw primary-path
          |  |     |  |  +--rw network-ref?
          |  |     |  |  |       -> /nw:networks/network/network-id
          |  |     |  |  +--rw path-element* [path-element-id]
          |  |     |  |     +--rw path-element-id              uint32
          |  |     |  |     +--rw (type)?
          |  |     |  |        +--:(numbered-node-hop)
          |  |     |  |        |  +--rw numbered-node-hop
          |  |     |  |        |     +--rw node-id     te-node-id
          |  |     |  |        |     +--rw hop-type?   te-hop-type
          |  |     |  |        +--:(numbered-link-hop)
          |  |     |  |        |  +--rw numbered-link-hop
          |  |     |  |        |     +--rw link-tp-id    te-tp-id
          |  |     |  |        |     +--rw hop-type?     te-hop-type
          |  |     |  |        |     +--rw direction?
          |  |     |  |        |             te-link-direction
          |  |     |  |        +--:(unnumbered-link-hop)
          |  |     |  |        |  +--rw unnumbered-link-hop
          |  |     |  |        |     +--rw link-tp-id    te-tp-id
          |  |     |  |        |     +--rw node-id       te-node-id
          |  |     |  |        |     +--rw hop-type?     te-hop-type
          |  |     |  |        |     +--rw direction?
          |  |     |  |        |             te-link-direction
          |  |     |  |        +--:(as-number)
          |  |     |  |        |  +--rw as-number-hop
          |  |     |  |        |     +--rw as-number    inet:as-number
          |  |     |  |        |     +--rw hop-type?    te-hop-type
          |  |     |  |        +--:(label)
          |  |     |  |           +--rw label-hop
          |  |     |  |              +--rw te-label
          |  |     |  |                 +--rw (technology)?
          |  |     |  |                 |  +--:(generic)
          |  |     |  |                 |     +--rw generic?
          |  |     |  |                 |             rt-types:generalized-label
          |  |     |  |                 +--rw direction?
          |  |     |  |                         te-label-direction
          |  |     |  +--rw backup-path* [index]
          |  |     |  |  +--rw index           uint32
          |  |     |  |  +--rw network-ref?
          |  |     |  |  |       -> /nw:networks/network/network-id
          |  |     |  |  +--rw path-element* [path-element-id]
          |  |     |  |     +--rw path-element-id              uint32
          |  |     |  |     +--rw (type)?
          |  |     |  |        +--:(numbered-node-hop)
          |  |     |  |        |  +--rw numbered-node-hop
          |  |     |  |        |     +--rw node-id     te-node-id
          |  |     |  |        |     +--rw hop-type?   te-hop-type
          |  |     |  |        +--:(numbered-link-hop)
          |  |     |  |        |  +--rw numbered-link-hop
          |  |     |  |        |     +--rw link-tp-id    te-tp-id
          |  |     |  |        |     +--rw hop-type?     te-hop-type
          |  |     |  |        |     +--rw direction?
          |  |     |  |        |             te-link-direction
          |  |     |  |        +--:(unnumbered-link-hop)
          |  |     |  |        |  +--rw unnumbered-link-hop
          |  |     |  |        |     +--rw link-tp-id    te-tp-id
          |  |     |  |        |     +--rw node-id       te-node-id
          |  |     |  |        |     +--rw hop-type?     te-hop-type
          |  |     |  |        |     +--rw direction?
          |  |     |  |        |             te-link-direction
          |  |     |  |        +--:(as-number)
          |  |     |  |        |  +--rw as-number-hop
          |  |     |  |        |     +--rw as-number    inet:as-number
          |  |     |  |        |     +--rw hop-type?    te-hop-type
          |  |     |  |        +--:(label)
          |  |     |  |           +--rw label-hop
          |  |     |  |              +--rw te-label
          |  |     |  |                 +--rw (technology)?
          |  |     |  |                 |  +--:(generic)
          |  |     |  |                 |     +--rw generic?
          |  |     |  |                 |             rt-types:generalized-label
          |  |     |  |                 +--rw direction?
          |  |     |  |                         te-label-direction
          |  |     |  +--rw protection-type?             identityref
          |  |     |  +--rw tunnel-termination-points
          |  |     |  |  +--rw source?        binary
          |  |     |  |  +--rw destination?   binary
          |  |     |  +--rw tunnels
          |  |     |     +--rw sharing?   boolean
          |  |     |     +--rw tunnel* [tunnel-name]
          |  |     |        +--rw tunnel-name    string
          |  |     |        +--rw sharing?       boolean
          |  |     +--rw path-constraints
          |  |     |  +--rw te-bandwidth
          |  |     |  |  +--rw (technology)?
          |  |     |  |     +--:(generic)
          |  |     |  |        +--rw generic?   te-bandwidth
          |  |     |  +--rw link-protection?          identityref
          |  |     |  +--rw setup-priority?           uint8
          |  |     |  +--rw hold-priority?            uint8
          |  |     |  +--rw signaling-type?           identityref
          |  |     |  +--rw path-metric-bounds
          |  |     |  |  +--rw path-metric-bound* [metric-type]
          |  |     |  |     +--rw metric-type    identityref
          |  |     |  |     +--rw upper-bound?   uint64
          |  |     |  +--rw path-affinities-values
          |  |     |  |  +--rw path-affinities-value* [usage]
          |  |     |  |     +--rw usage    identityref
          |  |     |  |     +--rw value?   admin-groups
          |  |     |  +--rw path-affinity-names
          |  |     |  |  +--rw path-affinity-name* [usage]
          |  |     |  |     +--rw usage            identityref
          |  |     |  |     +--rw affinity-name* [name]
          |  |     |  |        +--rw name    string
          |  |     |  +--rw path-srlgs-lists
          |  |     |  |  +--rw path-srlgs-list* [usage]
          |  |     |  |     +--rw usage     identityref
          |  |     |  |     +--rw values*   srlg
          |  |     |  +--rw path-srlgs-names
          |  |     |  |  +--rw path-srlgs-name* [usage]
          |  |     |  |     +--rw usage    identityref
          |  |     |  |     +--rw names*   string
          |  |     |  +--rw disjointness?
          |  |     |          te-path-disjointness
          |  |     +--rw optimizations
          |  |     |  +--rw (algorithm)?
          |  |     |     +--:(metric) {path-optimization-metric}?
          |  |     |     |  +--rw optimization-metric* [metric-type]
          |  |     |     |  |  +--rw metric-type
          |  |     |     |  |  |       identityref
          |  |     |     |  |  +--rw weight?
          |  |     |     |  |  |       uint8
          |  |     |     |  |  +--rw explicit-route-exclude-objects
          |  |     |     |  |  |  +--rw route-object-exclude-object*
          |  |     |     |  |  |          [index]
          |  |     |     |  |  |     +--rw index
          |  |     |     |  |  |     |       uint32
          |  |     |     |  |  |     +--rw (type)?
          |  |     |     |  |  |        +--:(numbered-node-hop)
          |  |     |     |  |  |        |  +--rw numbered-node-hop
          |  |     |     |  |  |        |     +--rw node-id
          |  |     |     |  |  |        |     |       te-node-id
          |  |     |     |  |  |        |     +--rw hop-type?
          |  |     |     |  |  |        |             te-hop-type
          |  |     |     |  |  |        +--:(numbered-link-hop)
          |  |     |     |  |  |        |  +--rw numbered-link-hop
          |  |     |     |  |  |        |     +--rw link-tp-id
          |  |     |     |  |  |        |     |       te-tp-id
          |  |     |     |  |  |        |     +--rw hop-type?
          |  |     |     |  |  |        |     |       te-hop-type
          |  |     |     |  |  |        |     +--rw direction?
          |  |     |     |  |  |        |             te-link-direction
          |  |     |     |  |  |        +--:(unnumbered-link-hop)
          |  |     |     |  |  |        |  +--rw unnumbered-link-hop
          |  |     |     |  |  |        |     +--rw link-tp-id
          |  |     |     |  |  |        |     |       te-tp-id
          |  |     |     |  |  |        |     +--rw node-id
          |  |     |     |  |  |        |     |       te-node-id
          |  |     |     |  |  |        |     +--rw hop-type?
          |  |     |     |  |  |        |     |       te-hop-type
          |  |     |     |  |  |        |     +--rw direction?
          |  |     |     |  |  |        |             te-link-direction
          |  |     |     |  |  |        +--:(as-number)
          |  |     |     |  |  |        |  +--rw as-number-hop
          |  |     |     |  |  |        |     +--rw as-number
          |  |     |     |  |  |        |     |       inet:as-number
          |  |     |     |  |  |        |     +--rw hop-type?
          |  |     |     |  |  |        |             te-hop-type
          |  |     |     |  |  |        +--:(label)
          |  |     |     |  |  |        |  +--rw label-hop
          |  |     |     |  |  |        |     +--rw te-label
          |  |     |     |  |  |        |        +--rw (technology)?
          |  |     |     |  |  |        |        |  +--:(generic)
          |  |     |     |  |  |        |        |     +--rw generic?
          |  |     |     |  |  |        |        |             rt-types:generalized-label
          |  |     |     |  |  |        |        +--rw direction?
          |  |     |     |  |  |        |                te-label-direction
          |  |     |     |  |  |        +--:(srlg)
          |  |     |     |  |  |           +--rw srlg
          |  |     |     |  |  |              +--rw srlg?   uint32
          |  |     |     |  |  +--rw explicit-route-include-objects
          |  |     |     |  |     +--rw route-object-include-object*
          |  |     |     |  |             [index]
          |  |     |     |  |        +--rw index
          |  |     |     |  |        |       uint32
          |  |     |     |  |        +--rw (type)?
          |  |     |     |  |           +--:(numbered-node-hop)
          |  |     |     |  |           |  +--rw numbered-node-hop
          |  |     |     |  |           |     +--rw node-id
          |  |     |     |  |           |     |       te-node-id
          |  |     |     |  |           |     +--rw hop-type?
          |  |     |     |  |           |             te-hop-type
          |  |     |     |  |           +--:(numbered-link-hop)
          |  |     |     |  |           |  +--rw numbered-link-hop
          |  |     |     |  |           |     +--rw link-tp-id
          |  |     |     |  |           |     |       te-tp-id
          |  |     |     |  |           |     +--rw hop-type?
          |  |     |     |  |           |     |       te-hop-type
          |  |     |     |  |           |     +--rw direction?
          |  |     |     |  |           |             te-link-direction
          |  |     |     |  |           +--:(unnumbered-link-hop)
          |  |     |     |  |           |  +--rw unnumbered-link-hop
          |  |     |     |  |           |     +--rw link-tp-id
          |  |     |     |  |           |     |       te-tp-id
          |  |     |     |  |           |     +--rw node-id
          |  |     |     |  |           |     |       te-node-id
          |  |     |     |  |           |     +--rw hop-type?
          |  |     |     |  |           |     |       te-hop-type
          |  |     |     |  |           |     +--rw direction?
          |  |     |     |  |           |             te-link-direction
          |  |     |     |  |           +--:(as-number)
          |  |     |     |  |           |  +--rw as-number-hop
          |  |     |     |  |           |     +--rw as-number
          |  |     |     |  |           |     |       inet:as-number
          |  |     |     |  |           |     +--rw hop-type?
          |  |     |     |  |           |             te-hop-type
          |  |     |     |  |           +--:(label)
          |  |     |     |  |              +--rw label-hop
          |  |     |     |  |                 +--rw te-label
          |  |     |     |  |                    +--rw (technology)?
          |  |     |     |  |                    |  +--:(generic)
          |  |     |     |  |                    |     +--rw generic?
          |  |     |     |  |                    |             rt-types:generalized-label
          |  |     |     |  |                    +--rw direction?
          |  |     |     |  |                            te-label-direction
          |  |     |     |  +--rw tiebreakers
          |  |     |     |     +--rw tiebreaker* [tiebreaker-type]
          |  |     |     |        +--rw tiebreaker-type    identityref
          |  |     |     +--:(objective-function)
          |  |     |              {path-optimization-objective-function}?
          |  |     |        +--rw objective-function
          |  |     |           +--rw objective-function-type?
          |  |     |                   identityref
          |  |     +--ro path-properties
          |  |        +--ro path-metric* [metric-type]
          |  |        |  +--ro metric-type           identityref
          |  |        |  +--ro accumulative-value?   uint64
          |  |        +--ro path-affinities-values
          |  |        |  +--ro path-affinities-value* [usage]
          |  |        |     +--ro usage    identityref
          |  |        |     +--ro value?   admin-groups
          |  |        +--ro path-affinity-names
          |  |        |  +--ro path-affinity-name* [usage]
          |  |        |     +--ro usage            identityref
          |  |        |     +--ro affinity-name* [name]
          |  |        |        +--ro name    string
          |  |        +--ro path-srlgs-lists
          |  |        |  +--ro path-srlgs-list* [usage]
          |  |        |     +--ro usage     identityref
          |  |        |     +--ro values*   srlg
          |  |        +--ro path-srlgs-names
          |  |        |  +--ro path-srlgs-name* [usage]
          |  |        |     +--ro usage    identityref
          |  |        |     +--ro names*   string
          |  |        +--ro path-route-objects
          |  |           +--ro path-route-object* [index]
          |  |              +--ro index                        uint32
          |  |              +--ro (type)?
          |  |                 +--:(numbered-node-hop)
          |  |                 |  +--ro numbered-node-hop
          |  |                 |     +--ro node-id     te-node-id
          |  |                 |     +--ro hop-type?   te-hop-type
          |  |                 +--:(numbered-link-hop)
          |  |                 |  +--ro numbered-link-hop
          |  |                 |     +--ro link-tp-id    te-tp-id
          |  |                 |     +--ro hop-type?     te-hop-type
          |  |                 |     +--ro direction?
          |  |                 |             te-link-direction
          |  |                 +--:(unnumbered-link-hop)
          |  |                 |  +--ro unnumbered-link-hop
          |  |                 |     +--ro link-tp-id    te-tp-id
          |  |                 |     +--ro node-id       te-node-id
          |  |                 |     +--ro hop-type?     te-hop-type
          |  |                 |     +--ro direction?
          |  |                 |             te-link-direction
          |  |                 +--:(as-number)
          |  |                 |  +--ro as-number-hop
          |  |                 |     +--ro as-number    inet:as-number
          |  |                 |     +--ro hop-type?    te-hop-type
          |  |                 +--:(label)
          |  |                    +--ro label-hop
          |  |                       +--ro te-label
          |  |                          +--ro (technology)?
          |  |                          |  +--:(generic)
          |  |                          |     +--ro generic?
          |  |                          |             rt-types:generalized-label
          |  |                          +--ro direction?
          |  |                                  te-label-direction
          |  +--rw domain-id?               uint32
          |  +--rw is-abstract?             empty
          |  +--rw name?                    string
          |  +--rw signaling-address*       inet:ip-address
          |  +--rw underlay-topology {te-topology-hierarchy}?
          |     +--rw network-ref?   -> /nw:networks/network/network-id
          +--ro oper-status?                   te-types:te-oper-status
          +--ro geolocation
          |  +--ro altitude?    int64
          |  +--ro latitude?    geographic-coordinate-degree
          |  +--ro longitude?   geographic-coordinate-degree
          +--ro is-multi-access-dr?            empty
          +--ro information-source?            te-info-source
          +--ro information-source-instance?   string
          +--ro information-source-state
          |  +--ro credibility-preference?    uint16
          |  +--ro logical-network-element?   string
          |  +--ro network-instance?          string
          |  +--ro topology
          |     +--ro node-ref?      leafref
          |     +--ro network-ref?   -> /nw:networks/network/network-id
          +--ro information-source-entry*
          |       [information-source information-source-instance]
          |  +--ro information-source             te-info-source
          |  +--ro information-source-instance    string
          |  +--ro information-source-state
          |  |  +--ro credibility-preference?    uint16
          |  |  +--ro logical-network-element?   string
          |  |  +--ro network-instance?          string
          |  |  +--ro topology
          |  |     +--ro node-ref?      leafref
          |  |     +--ro network-ref?
          |  |             -> /nw:networks/network/network-id
          |  +--ro connectivity-matrices
          |  |  +--ro number-of-entries?     uint16
          |  |  +--ro label-restrictions
          |  |  |  +--ro label-restriction* [index]
          |  |  |     +--ro restriction?    enumeration
          |  |  |     +--ro index           uint32
          |  |  |     +--ro label-start
          |  |  |     |  +--ro te-label
          |  |  |     |     +--ro (technology)?
          |  |  |     |     |  +--:(generic)
          |  |  |     |     |     +--ro generic?
          |  |  |     |     |             rt-types:generalized-label
          |  |  |     |     +--ro direction?       te-label-direction
          |  |  |     +--ro label-end
          |  |  |     |  +--ro te-label
          |  |  |     |     +--ro (technology)?
          |  |  |     |     |  +--:(generic)
          |  |  |     |     |     +--ro generic?
          |  |  |     |     |             rt-types:generalized-label
          |  |  |     |     +--ro direction?       te-label-direction
          |  |  |     +--ro label-step
          |  |  |     |  +--ro (technology)?
          |  |  |     |     +--:(generic)
          |  |  |     |        +--ro generic?   int32
          |  |  |     +--ro range-bitmap?   yang:hex-string
          |  |  +--ro is-allowed?            boolean
          |  |  +--ro underlay {te-topology-hierarchy}?
          |  |  |  +--ro enabled?                     boolean
          |  |  |  +--ro primary-path
          |  |  |  |  +--ro network-ref?
          |  |  |  |  |       -> /nw:networks/network/network-id
          |  |  |  |  +--ro path-element* [path-element-id]
          |  |  |  |     +--ro path-element-id              uint32
          |  |  |  |     +--ro (type)?
          |  |  |  |        +--:(numbered-node-hop)
          |  |  |  |        |  +--ro numbered-node-hop
          |  |  |  |        |     +--ro node-id     te-node-id
          |  |  |  |        |     +--ro hop-type?   te-hop-type
          |  |  |  |        +--:(numbered-link-hop)
          |  |  |  |        |  +--ro numbered-link-hop
          |  |  |  |        |     +--ro link-tp-id    te-tp-id
          |  |  |  |        |     +--ro hop-type?     te-hop-type
          |  |  |  |        |     +--ro direction?    te-link-direction
          |  |  |  |        +--:(unnumbered-link-hop)
          |  |  |  |        |  +--ro unnumbered-link-hop
          |  |  |  |        |     +--ro link-tp-id    te-tp-id
          |  |  |  |        |     +--ro node-id       te-node-id
          |  |  |  |        |     +--ro hop-type?     te-hop-type
          |  |  |  |        |     +--ro direction?    te-link-direction
          |  |  |  |        +--:(as-number)
          |  |  |  |        |  +--ro as-number-hop
          |  |  |  |        |     +--ro as-number    inet:as-number
          |  |  |  |        |     +--ro hop-type?    te-hop-type
          |  |  |  |        +--:(label)
          |  |  |  |           +--ro label-hop
          |  |  |  |              +--ro te-label
          |  |  |  |                 +--ro (technology)?
          |  |  |  |                 |  +--:(generic)
          |  |  |  |                 |     +--ro generic?
          |  |  |  |                 |             rt-types:generalized-label
          |  |  |  |                 +--ro direction?
          |  |  |  |                         te-label-direction
          |  |  |  +--ro backup-path* [index]
          |  |  |  |  +--ro index           uint32
          |  |  |  |  +--ro network-ref?
          |  |  |  |  |       -> /nw:networks/network/network-id
          |  |  |  |  +--ro path-element* [path-element-id]
          |  |  |  |     +--ro path-element-id              uint32
          |  |  |  |     +--ro (type)?
          |  |  |  |        +--:(numbered-node-hop)
          |  |  |  |        |  +--ro numbered-node-hop
          |  |  |  |        |     +--ro node-id     te-node-id
          |  |  |  |        |     +--ro hop-type?   te-hop-type
          |  |  |  |        +--:(numbered-link-hop)
          |  |  |  |        |  +--ro numbered-link-hop
          |  |  |  |        |     +--ro link-tp-id    te-tp-id
          |  |  |  |        |     +--ro hop-type?     te-hop-type
          |  |  |  |        |     +--ro direction?    te-link-direction
          |  |  |  |        +--:(unnumbered-link-hop)
          |  |  |  |        |  +--ro unnumbered-link-hop
          |  |  |  |        |     +--ro link-tp-id    te-tp-id
          |  |  |  |        |     +--ro node-id       te-node-id
          |  |  |  |        |     +--ro hop-type?     te-hop-type
          |  |  |  |        |     +--ro direction?    te-link-direction
          |  |  |  |        +--:(as-number)
          |  |  |  |        |  +--ro as-number-hop
          |  |  |  |        |     +--ro as-number    inet:as-number
          |  |  |  |        |     +--ro hop-type?    te-hop-type
          |  |  |  |        +--:(label)
          |  |  |  |           +--ro label-hop
          |  |  |  |              +--ro te-label
          |  |  |  |                 +--ro (technology)?
          |  |  |  |                 |  +--:(generic)
          |  |  |  |                 |     +--ro generic?
          |  |  |  |                 |             rt-types:generalized-label
          |  |  |  |                 +--ro direction?
          |  |  |  |                         te-label-direction
          |  |  |  +--ro protection-type?             identityref
          |  |  |  +--ro tunnel-termination-points
          |  |  |  |  +--ro source?        binary
          |  |  |  |  +--ro destination?   binary
          |  |  |  +--ro tunnels
          |  |  |     +--ro sharing?   boolean
          |  |  |     +--ro tunnel* [tunnel-name]
          |  |  |        +--ro tunnel-name    string
          |  |  |        +--ro sharing?       boolean
          |  |  +--ro path-constraints
          |  |  |  +--ro te-bandwidth
          |  |  |  |  +--ro (technology)?
          |  |  |  |     +--:(generic)
          |  |  |  |        +--ro generic?   te-bandwidth
          |  |  |  +--ro link-protection?          identityref
          |  |  |  +--ro setup-priority?           uint8
          |  |  |  +--ro hold-priority?            uint8
          |  |  |  +--ro signaling-type?           identityref
          |  |  |  +--ro path-metric-bounds
          |  |  |  |  +--ro path-metric-bound* [metric-type]
          |  |  |  |     +--ro metric-type    identityref
          |  |  |  |     +--ro upper-bound?   uint64
          |  |  |  +--ro path-affinities-values
          |  |  |  |  +--ro path-affinities-value* [usage]
          |  |  |  |     +--ro usage    identityref
          |  |  |  |     +--ro value?   admin-groups
          |  |  |  +--ro path-affinity-names
          |  |  |  |  +--ro path-affinity-name* [usage]
          |  |  |  |     +--ro usage            identityref
          |  |  |  |     +--ro affinity-name* [name]
          |  |  |  |        +--ro name    string
          |  |  |  +--ro path-srlgs-lists
          |  |  |  |  +--ro path-srlgs-list* [usage]
          |  |  |  |     +--ro usage     identityref
          |  |  |  |     +--ro values*   srlg
          |  |  |  +--ro path-srlgs-names
          |  |  |  |  +--ro path-srlgs-name* [usage]
          |  |  |  |     +--ro usage    identityref
          |  |  |  |     +--ro names*   string
          |  |  |  +--ro disjointness?             te-path-disjointness
          |  |  +--ro optimizations
          |  |  |  +--ro (algorithm)?
          |  |  |     +--:(metric) {path-optimization-metric}?
          |  |  |     |  +--ro optimization-metric* [metric-type]
          |  |  |     |  |  +--ro metric-type
          |  |  |     |  |  |       identityref
          |  |  |     |  |  +--ro weight?
          |  |  |     |  |  |       uint8
          |  |  |     |  |  +--ro explicit-route-exclude-objects
          |  |  |     |  |  |  +--ro route-object-exclude-object*
          |  |  |     |  |  |          [index]
          |  |  |     |  |  |     +--ro index
          |  |  |     |  |  |     |       uint32
          |  |  |     |  |  |     +--ro (type)?
          |  |  |     |  |  |        +--:(numbered-node-hop)
          |  |  |     |  |  |        |  +--ro numbered-node-hop
          |  |  |     |  |  |        |     +--ro node-id     te-node-id
          |  |  |     |  |  |        |     +--ro hop-type?   te-hop-type
          |  |  |     |  |  |        +--:(numbered-link-hop)
          |  |  |     |  |  |        |  +--ro numbered-link-hop
          |  |  |     |  |  |        |     +--ro link-tp-id    te-tp-id
          |  |  |     |  |  |        |     +--ro hop-type?
          |  |  |     |  |  |        |     |       te-hop-type
          |  |  |     |  |  |        |     +--ro direction?
          |  |  |     |  |  |        |             te-link-direction
          |  |  |     |  |  |        +--:(unnumbered-link-hop)
          |  |  |     |  |  |        |  +--ro unnumbered-link-hop
          |  |  |     |  |  |        |     +--ro link-tp-id    te-tp-id
          |  |  |     |  |  |        |     +--ro node-id
          |  |  |     |  |  |        |     |       te-node-id
          |  |  |     |  |  |        |     +--ro hop-type?
          |  |  |     |  |  |        |     |       te-hop-type
          |  |  |     |  |  |        |     +--ro direction?
          |  |  |     |  |  |        |             te-link-direction
          |  |  |     |  |  |        +--:(as-number)
          |  |  |     |  |  |        |  +--ro as-number-hop
          |  |  |     |  |  |        |     +--ro as-number
          |  |  |     |  |  |        |     |       inet:as-number
          |  |  |     |  |  |        |     +--ro hop-type?
          |  |  |     |  |  |        |             te-hop-type
          |  |  |     |  |  |        +--:(label)
          |  |  |     |  |  |        |  +--ro label-hop
          |  |  |     |  |  |        |     +--ro te-label
          |  |  |     |  |  |        |        +--ro (technology)?
          |  |  |     |  |  |        |        |  +--:(generic)
          |  |  |     |  |  |        |        |     +--ro generic?
          |  |  |     |  |  |        |        |             rt-types:generalized-label
          |  |  |     |  |  |        |        +--ro direction?
          |  |  |     |  |  |        |                te-label-direction
          |  |  |     |  |  |        +--:(srlg)
          |  |  |     |  |  |           +--ro srlg
          |  |  |     |  |  |              +--ro srlg?   uint32
          |  |  |     |  |  +--ro explicit-route-include-objects
          |  |  |     |  |     +--ro route-object-include-object*
          |  |  |     |  |             [index]
          |  |  |     |  |        +--ro index
          |  |  |     |  |        |       uint32
          |  |  |     |  |        +--ro (type)?
          |  |  |     |  |           +--:(numbered-node-hop)
          |  |  |     |  |           |  +--ro numbered-node-hop
          |  |  |     |  |           |     +--ro node-id     te-node-id
          |  |  |     |  |           |     +--ro hop-type?   te-hop-type
          |  |  |     |  |           +--:(numbered-link-hop)
          |  |  |     |  |           |  +--ro numbered-link-hop
          |  |  |     |  |           |     +--ro link-tp-id    te-tp-id
          |  |  |     |  |           |     +--ro hop-type?
          |  |  |     |  |           |     |       te-hop-type
          |  |  |     |  |           |     +--ro direction?
          |  |  |     |  |           |             te-link-direction
          |  |  |     |  |           +--:(unnumbered-link-hop)
          |  |  |     |  |           |  +--ro unnumbered-link-hop
          |  |  |     |  |           |     +--ro link-tp-id    te-tp-id
          |  |  |     |  |           |     +--ro node-id
          |  |  |     |  |           |     |       te-node-id
          |  |  |     |  |           |     +--ro hop-type?
          |  |  |     |  |           |     |       te-hop-type
          |  |  |     |  |           |     +--ro direction?
          |  |  |     |  |           |             te-link-direction
          |  |  |     |  |           +--:(as-number)
          |  |  |     |  |           |  +--ro as-number-hop
          |  |  |     |  |           |     +--ro as-number
          |  |  |     |  |           |     |       inet:as-number
          |  |  |     |  |           |     +--ro hop-type?
          |  |  |     |  |           |             te-hop-type
          |  |  |     |  |           +--:(label)
          |  |  |     |  |              +--ro label-hop
          |  |  |     |  |                 +--ro te-label
          |  |  |     |  |                    +--ro (technology)?
          |  |  |     |  |                    |  +--:(generic)
          |  |  |     |  |                    |     +--ro generic?
          |  |  |     |  |                    |             rt-types:generalized-label
          |  |  |     |  |                    +--ro direction?
          |  |  |     |  |                            te-label-direction
          |  |  |     |  +--ro tiebreakers
          |  |  |     |     +--ro tiebreaker* [tiebreaker-type]
          |  |  |     |        +--ro tiebreaker-type    identityref
          |  |  |     +--:(objective-function)
          |  |  |              {path-optimization-objective-function}?
          |  |  |        +--ro objective-function
          |  |  |           +--ro objective-function-type?   identityref
          |  |  +--ro path-properties
          |  |  |  +--ro path-metric* [metric-type]
          |  |  |  |  +--ro metric-type           identityref
          |  |  |  |  +--ro accumulative-value?   uint64
          |  |  |  +--ro path-affinities-values
          |  |  |  |  +--ro path-affinities-value* [usage]
          |  |  |  |     +--ro usage    identityref
          |  |  |  |     +--ro value?   admin-groups
          |  |  |  +--ro path-affinity-names
          |  |  |  |  +--ro path-affinity-name* [usage]
          |  |  |  |     +--ro usage            identityref
          |  |  |  |     +--ro affinity-name* [name]
          |  |  |  |        +--ro name    string
          |  |  |  +--ro path-srlgs-lists
          |  |  |  |  +--ro path-srlgs-list* [usage]
          |  |  |  |     +--ro usage     identityref
          |  |  |  |     +--ro values*   srlg
          |  |  |  +--ro path-srlgs-names
          |  |  |  |  +--ro path-srlgs-name* [usage]
          |  |  |  |     +--ro usage    identityref
          |  |  |  |     +--ro names*   string
          |  |  |  +--ro path-route-objects
          |  |  |     +--ro path-route-object* [index]
          |  |  |        +--ro index                        uint32
          |  |  |        +--ro (type)?
          |  |  |           +--:(numbered-node-hop)
          |  |  |           |  +--ro numbered-node-hop
          |  |  |           |     +--ro node-id     te-node-id
          |  |  |           |     +--ro hop-type?   te-hop-type
          |  |  |           +--:(numbered-link-hop)
          |  |  |           |  +--ro numbered-link-hop
          |  |  |           |     +--ro link-tp-id    te-tp-id
          |  |  |           |     +--ro hop-type?     te-hop-type
          |  |  |           |     +--ro direction?    te-link-direction
          |  |  |           +--:(unnumbered-link-hop)
          |  |  |           |  +--ro unnumbered-link-hop
          |  |  |           |     +--ro link-tp-id    te-tp-id
          |  |  |           |     +--ro node-id       te-node-id
          |  |  |           |     +--ro hop-type?     te-hop-type
          |  |  |           |     +--ro direction?    te-link-direction
          |  |  |           +--:(as-number)
          |  |  |           |  +--ro as-number-hop
          |  |  |           |     +--ro as-number    inet:as-number
          |  |  |           |     +--ro hop-type?    te-hop-type
          |  |  |           +--:(label)
          |  |  |              +--ro label-hop
          |  |  |                 +--ro te-label
          |  |  |                    +--ro (technology)?
          |  |  |                    |  +--:(generic)
          |  |  |                    |     +--ro generic?
          |  |  |                    |             rt-types:generalized-label
          |  |  |                    +--ro direction?
          |  |  |                            te-label-direction
          |  |  +--ro connectivity-matrix* [id]
          |  |     +--ro id                  uint32
          |  |     +--ro from
          |  |     |  +--ro tp-ref?               leafref
          |  |     |  +--ro label-restrictions
          |  |     |     +--ro label-restriction* [index]
          |  |     |        +--ro restriction?    enumeration
          |  |     |        +--ro index           uint32
          |  |     |        +--ro label-start
          |  |     |        |  +--ro te-label
          |  |     |        |     +--ro (technology)?
          |  |     |        |     |  +--:(generic)
          |  |     |        |     |     +--ro generic?
          |  |     |        |     |             rt-types:generalized-label
          |  |     |        |     +--ro direction?
          |  |     |        |             te-label-direction
          |  |     |        +--ro label-end
          |  |     |        |  +--ro te-label
          |  |     |        |     +--ro (technology)?
          |  |     |        |     |  +--:(generic)
          |  |     |        |     |     +--ro generic?
          |  |     |        |     |             rt-types:generalized-label
          |  |     |        |     +--ro direction?
          |  |     |        |             te-label-direction
          |  |     |        +--ro label-step
          |  |     |        |  +--ro (technology)?
          |  |     |        |     +--:(generic)
          |  |     |        |        +--ro generic?   int32
          |  |     |        +--ro range-bitmap?   yang:hex-string
          |  |     +--ro to
          |  |     |  +--ro tp-ref?               leafref
          |  |     |  +--ro label-restrictions
          |  |     |     +--ro label-restriction* [index]
          |  |     |        +--ro restriction?    enumeration
          |  |     |        +--ro index           uint32
          |  |     |        +--ro label-start
          |  |     |        |  +--ro te-label
          |  |     |        |     +--ro (technology)?
          |  |     |        |     |  +--:(generic)
          |  |     |        |     |     +--ro generic?
          |  |     |        |     |             rt-types:generalized-label
          |  |     |        |     +--ro direction?
          |  |     |        |             te-label-direction
          |  |     |        +--ro label-end
          |  |     |        |  +--ro te-label
          |  |     |        |     +--ro (technology)?
          |  |     |        |     |  +--:(generic)
          |  |     |        |     |     +--ro generic?
          |  |     |        |     |             rt-types:generalized-label
          |  |     |        |     +--ro direction?
          |  |     |        |             te-label-direction
          |  |     |        +--ro label-step
          |  |     |        |  +--ro (technology)?
          |  |     |        |     +--:(generic)
          |  |     |        |        +--ro generic?   int32
          |  |     |        +--ro range-bitmap?   yang:hex-string
          |  |     +--ro is-allowed?         boolean
          |  |     +--ro underlay {te-topology-hierarchy}?
          |  |     |  +--ro enabled?                     boolean
          |  |     |  +--ro primary-path
          |  |     |  |  +--ro network-ref?
          |  |     |  |  |       -> /nw:networks/network/network-id
          |  |     |  |  +--ro path-element* [path-element-id]
          |  |     |  |     +--ro path-element-id              uint32
          |  |     |  |     +--ro (type)?
          |  |     |  |        +--:(numbered-node-hop)
          |  |     |  |        |  +--ro numbered-node-hop
          |  |     |  |        |     +--ro node-id     te-node-id
          |  |     |  |        |     +--ro hop-type?   te-hop-type
          |  |     |  |        +--:(numbered-link-hop)
          |  |     |  |        |  +--ro numbered-link-hop
          |  |     |  |        |     +--ro link-tp-id    te-tp-id
          |  |     |  |        |     +--ro hop-type?     te-hop-type
          |  |     |  |        |     +--ro direction?
          |  |     |  |        |             te-link-direction
          |  |     |  |        +--:(unnumbered-link-hop)
          |  |     |  |        |  +--ro unnumbered-link-hop
          |  |     |  |        |     +--ro link-tp-id    te-tp-id
          |  |     |  |        |     +--ro node-id       te-node-id
          |  |     |  |        |     +--ro hop-type?     te-hop-type
          |  |     |  |        |     +--ro direction?
          |  |     |  |        |             te-link-direction
          |  |     |  |        +--:(as-number)
          |  |     |  |        |  +--ro as-number-hop
          |  |     |  |        |     +--ro as-number    inet:as-number
          |  |     |  |        |     +--ro hop-type?    te-hop-type
          |  |     |  |        +--:(label)
          |  |     |  |           +--ro label-hop
          |  |     |  |              +--ro te-label
          |  |     |  |                 +--ro (technology)?
          |  |     |  |                 |  +--:(generic)
          |  |     |  |                 |     +--ro generic?
          |  |     |  |                 |             rt-types:generalized-label
          |  |     |  |                 +--ro direction?
          |  |     |  |                         te-label-direction
          |  |     |  +--ro backup-path* [index]
          |  |     |  |  +--ro index           uint32
          |  |     |  |  +--ro network-ref?
          |  |     |  |  |       -> /nw:networks/network/network-id
          |  |     |  |  +--ro path-element* [path-element-id]
          |  |     |  |     +--ro path-element-id              uint32
          |  |     |  |     +--ro (type)?
          |  |     |  |        +--:(numbered-node-hop)
          |  |     |  |        |  +--ro numbered-node-hop
          |  |     |  |        |     +--ro node-id     te-node-id
          |  |     |  |        |     +--ro hop-type?   te-hop-type
          |  |     |  |        +--:(numbered-link-hop)
          |  |     |  |        |  +--ro numbered-link-hop
          |  |     |  |        |     +--ro link-tp-id    te-tp-id
          |  |     |  |        |     +--ro hop-type?     te-hop-type
          |  |     |  |        |     +--ro direction?
          |  |     |  |        |             te-link-direction
          |  |     |  |        +--:(unnumbered-link-hop)
          |  |     |  |        |  +--ro unnumbered-link-hop
          |  |     |  |        |     +--ro link-tp-id    te-tp-id
          |  |     |  |        |     +--ro node-id       te-node-id
          |  |     |  |        |     +--ro hop-type?     te-hop-type
          |  |     |  |        |     +--ro direction?
          |  |     |  |        |             te-link-direction
          |  |     |  |        +--:(as-number)
          |  |     |  |        |  +--ro as-number-hop
          |  |     |  |        |     +--ro as-number    inet:as-number
          |  |     |  |        |     +--ro hop-type?    te-hop-type
          |  |     |  |        +--:(label)
          |  |     |  |           +--ro label-hop
          |  |     |  |              +--ro te-label
          |  |     |  |                 +--ro (technology)?
          |  |     |  |                 |  +--:(generic)
          |  |     |  |                 |     +--ro generic?
          |  |     |  |                 |             rt-types:generalized-label
          |  |     |  |                 +--ro direction?
          |  |     |  |                         te-label-direction
          |  |     |  +--ro protection-type?             identityref
          |  |     |  +--ro tunnel-termination-points
          |  |     |  |  +--ro source?        binary
          |  |     |  |  +--ro destination?   binary
          |  |     |  +--ro tunnels
          |  |     |     +--ro sharing?   boolean
          |  |     |     +--ro tunnel* [tunnel-name]
          |  |     |        +--ro tunnel-name    string
          |  |     |        +--ro sharing?       boolean
          |  |     +--ro path-constraints
          |  |     |  +--ro te-bandwidth
          |  |     |  |  +--ro (technology)?
          |  |     |  |     +--:(generic)
          |  |     |  |        +--ro generic?   te-bandwidth
          |  |     |  +--ro link-protection?          identityref
          |  |     |  +--ro setup-priority?           uint8
          |  |     |  +--ro hold-priority?            uint8
          |  |     |  +--ro signaling-type?           identityref
          |  |     |  +--ro path-metric-bounds
          |  |     |  |  +--ro path-metric-bound* [metric-type]
          |  |     |  |     +--ro metric-type    identityref
          |  |     |  |     +--ro upper-bound?   uint64
          |  |     |  +--ro path-affinities-values
          |  |     |  |  +--ro path-affinities-value* [usage]
          |  |     |  |     +--ro usage    identityref
          |  |     |  |     +--ro value?   admin-groups
          |  |     |  +--ro path-affinity-names
          |  |     |  |  +--ro path-affinity-name* [usage]
          |  |     |  |     +--ro usage            identityref
          |  |     |  |     +--ro affinity-name* [name]
          |  |     |  |        +--ro name    string
          |  |     |  +--ro path-srlgs-lists
          |  |     |  |  +--ro path-srlgs-list* [usage]
          |  |     |  |     +--ro usage     identityref
          |  |     |  |     +--ro values*   srlg
          |  |     |  +--ro path-srlgs-names
          |  |     |  |  +--ro path-srlgs-name* [usage]
          |  |     |  |     +--ro usage    identityref
          |  |     |  |     +--ro names*   string
          |  |     |  +--ro disjointness?
          |  |     |          te-path-disjointness
          |  |     +--ro optimizations
          |  |     |  +--ro (algorithm)?
          |  |     |     +--:(metric) {path-optimization-metric}?
          |  |     |     |  +--ro optimization-metric* [metric-type]
          |  |     |     |  |  +--ro metric-type
          |  |     |     |  |  |       identityref
          |  |     |     |  |  +--ro weight?
          |  |     |     |  |  |       uint8
          |  |     |     |  |  +--ro explicit-route-exclude-objects
          |  |     |     |  |  |  +--ro route-object-exclude-object*
          |  |     |     |  |  |          [index]
          |  |     |     |  |  |     +--ro index
          |  |     |     |  |  |     |       uint32
          |  |     |     |  |  |     +--ro (type)?
          |  |     |     |  |  |        +--:(numbered-node-hop)
          |  |     |     |  |  |        |  +--ro numbered-node-hop
          |  |     |     |  |  |        |     +--ro node-id
          |  |     |     |  |  |        |     |       te-node-id
          |  |     |     |  |  |        |     +--ro hop-type?
          |  |     |     |  |  |        |             te-hop-type
          |  |     |     |  |  |        +--:(numbered-link-hop)
          |  |     |     |  |  |        |  +--ro numbered-link-hop
          |  |     |     |  |  |        |     +--ro link-tp-id
          |  |     |     |  |  |        |     |       te-tp-id
          |  |     |     |  |  |        |     +--ro hop-type?
          |  |     |     |  |  |        |     |       te-hop-type
          |  |     |     |  |  |        |     +--ro direction?
          |  |     |     |  |  |        |             te-link-direction
          |  |     |     |  |  |        +--:(unnumbered-link-hop)
          |  |     |     |  |  |        |  +--ro unnumbered-link-hop
          |  |     |     |  |  |        |     +--ro link-tp-id
          |  |     |     |  |  |        |     |       te-tp-id
          |  |     |     |  |  |        |     +--ro node-id
          |  |     |     |  |  |        |     |       te-node-id
          |  |     |     |  |  |        |     +--ro hop-type?
          |  |     |     |  |  |        |     |       te-hop-type
          |  |     |     |  |  |        |     +--ro direction?
          |  |     |     |  |  |        |             te-link-direction
          |  |     |     |  |  |        +--:(as-number)
          |  |     |     |  |  |        |  +--ro as-number-hop
          |  |     |     |  |  |        |     +--ro as-number
          |  |     |     |  |  |        |     |       inet:as-number
          |  |     |     |  |  |        |     +--ro hop-type?
          |  |     |     |  |  |        |             te-hop-type
          |  |     |     |  |  |        +--:(label)
          |  |     |     |  |  |        |  +--ro label-hop
          |  |     |     |  |  |        |     +--ro te-label
          |  |     |     |  |  |        |        +--ro (technology)?
          |  |     |     |  |  |        |        |  +--:(generic)
          |  |     |     |  |  |        |        |     +--ro generic?
          |  |     |     |  |  |        |        |             rt-types:generalized-label
          |  |     |     |  |  |        |        +--ro direction?
          |  |     |     |  |  |        |                te-label-direction
          |  |     |     |  |  |        +--:(srlg)
          |  |     |     |  |  |           +--ro srlg
          |  |     |     |  |  |              +--ro srlg?   uint32
          |  |     |     |  |  +--ro explicit-route-include-objects
          |  |     |     |  |     +--ro route-object-include-object*
          |  |     |     |  |             [index]
          |  |     |     |  |        +--ro index
          |  |     |     |  |        |       uint32
          |  |     |     |  |        +--ro (type)?
          |  |     |     |  |           +--:(numbered-node-hop)
          |  |     |     |  |           |  +--ro numbered-node-hop
          |  |     |     |  |           |     +--ro node-id
          |  |     |     |  |           |     |       te-node-id
          |  |     |     |  |           |     +--ro hop-type?
          |  |     |     |  |           |             te-hop-type
          |  |     |     |  |           +--:(numbered-link-hop)
          |  |     |     |  |           |  +--ro numbered-link-hop
          |  |     |     |  |           |     +--ro link-tp-id
          |  |     |     |  |           |     |       te-tp-id
          |  |     |     |  |           |     +--ro hop-type?
          |  |     |     |  |           |     |       te-hop-type
          |  |     |     |  |           |     +--ro direction?
          |  |     |     |  |           |             te-link-direction
          |  |     |     |  |           +--:(unnumbered-link-hop)
          |  |     |     |  |           |  +--ro unnumbered-link-hop
          |  |     |     |  |           |     +--ro link-tp-id
          |  |     |     |  |           |     |       te-tp-id
          |  |     |     |  |           |     +--ro node-id
          |  |     |     |  |           |     |       te-node-id
          |  |     |     |  |           |     +--ro hop-type?
          |  |     |     |  |           |     |       te-hop-type
          |  |     |     |  |           |     +--ro direction?
          |  |     |     |  |           |             te-link-direction
          |  |     |     |  |           +--:(as-number)
          |  |     |     |  |           |  +--ro as-number-hop
          |  |     |     |  |           |     +--ro as-number
          |  |     |     |  |           |     |       inet:as-number
          |  |     |     |  |           |     +--ro hop-type?
          |  |     |     |  |           |             te-hop-type
          |  |     |     |  |           +--:(label)
          |  |     |     |  |              +--ro label-hop
          |  |     |     |  |                 +--ro te-label
          |  |     |     |  |                    +--ro (technology)?
          |  |     |     |  |                    |  +--:(generic)
          |  |     |     |  |                    |     +--ro generic?
          |  |     |     |  |                    |             rt-types:generalized-label
          |  |     |     |  |                    +--ro direction?
          |  |     |     |  |                            te-label-direction
          |  |     |     |  +--ro tiebreakers
          |  |     |     |     +--ro tiebreaker* [tiebreaker-type]
          |  |     |     |        +--ro tiebreaker-type    identityref
          |  |     |     +--:(objective-function)
          |  |     |              {path-optimization-objective-function}?
          |  |     |        +--ro objective-function
          |  |     |           +--ro objective-function-type?
          |  |     |                   identityref
          |  |     +--ro path-properties
          |  |        +--ro path-metric* [metric-type]
          |  |        |  +--ro metric-type           identityref
          |  |        |  +--ro accumulative-value?   uint64
          |  |        +--ro path-affinities-values
          |  |        |  +--ro path-affinities-value* [usage]
          |  |        |     +--ro usage    identityref
          |  |        |     +--ro value?   admin-groups
          |  |        +--ro path-affinity-names
          |  |        |  +--ro path-affinity-name* [usage]
          |  |        |     +--ro usage            identityref
          |  |        |     +--ro affinity-name* [name]
          |  |        |        +--ro name    string
          |  |        +--ro path-srlgs-lists
          |  |        |  +--ro path-srlgs-list* [usage]
          |  |        |     +--ro usage     identityref
          |  |        |     +--ro values*   srlg
          |  |        +--ro path-srlgs-names
          |  |        |  +--ro path-srlgs-name* [usage]
          |  |        |     +--ro usage    identityref
          |  |        |     +--ro names*   string
          |  |        +--ro path-route-objects
          |  |           +--ro path-route-object* [index]
          |  |              +--ro index                        uint32
          |  |              +--ro (type)?
          |  |                 +--:(numbered-node-hop)
          |  |                 |  +--ro numbered-node-hop
          |  |                 |     +--ro node-id     te-node-id
          |  |                 |     +--ro hop-type?   te-hop-type
          |  |                 +--:(numbered-link-hop)
          |  |                 |  +--ro numbered-link-hop
          |  |                 |     +--ro link-tp-id    te-tp-id
          |  |                 |     +--ro hop-type?     te-hop-type
          |  |                 |     +--ro direction?
          |  |                 |             te-link-direction
          |  |                 +--:(unnumbered-link-hop)
          |  |                 |  +--ro unnumbered-link-hop
          |  |                 |     +--ro link-tp-id    te-tp-id
          |  |                 |     +--ro node-id       te-node-id
          |  |                 |     +--ro hop-type?     te-hop-type
          |  |                 |     +--ro direction?
          |  |                 |             te-link-direction
          |  |                 +--:(as-number)
          |  |                 |  +--ro as-number-hop
          |  |                 |     +--ro as-number    inet:as-number
          |  |                 |     +--ro hop-type?    te-hop-type
          |  |                 +--:(label)
          |  |                    +--ro label-hop
          |  |                       +--ro te-label
          |  |                          +--ro (technology)?
          |  |                          |  +--:(generic)
          |  |                          |     +--ro generic?
          |  |                          |             rt-types:generalized-label
          |  |                          +--ro direction?
          |  |                                  te-label-direction
          |  +--ro domain-id?                     uint32
          |  +--ro is-abstract?                   empty
          |  +--ro name?                          string
          |  +--ro signaling-address*             inet:ip-address
          |  +--ro underlay-topology {te-topology-hierarchy}?
          |     +--ro network-ref?   -> /nw:networks/network/network-id
          +--ro statistics
          |  +--ro discontinuity-time?          yang:date-and-time
          |  +--ro node
          |  |  +--ro disables?             yang:counter32
          |  |  +--ro enables?              yang:counter32
          |  |  +--ro maintenance-sets?     yang:counter32
          |  |  +--ro maintenance-clears?   yang:counter32
          |  |  +--ro modifies?             yang:counter32
          |  +--ro connectivity-matrix-entry
          |     +--ro creates?    yang:counter32
          |     +--ro deletes?    yang:counter32
          |     +--ro disables?   yang:counter32
          |     +--ro enables?    yang:counter32
          |     +--ro modifies?   yang:counter32
          +--rw tunnel-termination-point* [tunnel-tp-id]
             +--rw tunnel-tp-id                           binary
             +--rw admin-status?
             |       te-types:te-admin-status
             +--rw name?                                  string
             +--rw switching-capability?                  identityref
             +--rw encoding?                              identityref
             +--rw inter-layer-lock-id*                   uint32
             +--rw protection-type?                       identityref
             +--rw client-layer-adaptation
             |  +--rw switching-capability*
             |          [switching-capability encoding]
             |     +--rw switching-capability    identityref
             |     +--rw encoding                identityref
             |     +--rw te-bandwidth
             |        +--rw (technology)?
             |           +--:(generic)
             |              +--rw generic?   te-bandwidth
             +--rw local-link-connectivities
             |  +--rw number-of-entries?         uint16
             |  +--rw label-restrictions
             |  |  +--rw label-restriction* [index]
             |  |     +--rw restriction?    enumeration
             |  |     +--rw index           uint32
             |  |     +--rw label-start
             |  |     |  +--rw te-label
             |  |     |     +--rw (technology)?
             |  |     |     |  +--:(generic)
             |  |     |     |     +--rw generic?
             |  |     |     |             rt-types:generalized-label
             |  |     |     +--rw direction?       te-label-direction
             |  |     +--rw label-end
             |  |     |  +--rw te-label
             |  |     |     +--rw (technology)?
             |  |     |     |  +--:(generic)
             |  |     |     |     +--rw generic?
             |  |     |     |             rt-types:generalized-label
             |  |     |     +--rw direction?       te-label-direction
             |  |     +--rw label-step
             |  |     |  +--rw (technology)?
             |  |     |     +--:(generic)
             |  |     |        +--rw generic?   int32
             |  |     +--rw range-bitmap?   yang:hex-string
             |  +--rw is-allowed?                boolean
             |  +--rw underlay {te-topology-hierarchy}?
             |  |  +--rw enabled?                     boolean
             |  |  +--rw primary-path
             |  |  |  +--rw network-ref?
             |  |  |  |       -> /nw:networks/network/network-id
             |  |  |  +--rw path-element* [path-element-id]
             |  |  |     +--rw path-element-id              uint32
             |  |  |     +--rw (type)?
             |  |  |        +--:(numbered-node-hop)
             |  |  |        |  +--rw numbered-node-hop
             |  |  |        |     +--rw node-id     te-node-id
             |  |  |        |     +--rw hop-type?   te-hop-type
             |  |  |        +--:(numbered-link-hop)
             |  |  |        |  +--rw numbered-link-hop
             |  |  |        |     +--rw link-tp-id    te-tp-id
             |  |  |        |     +--rw hop-type?     te-hop-type
             |  |  |        |     +--rw direction?    te-link-direction
             |  |  |        +--:(unnumbered-link-hop)
             |  |  |        |  +--rw unnumbered-link-hop
             |  |  |        |     +--rw link-tp-id    te-tp-id
             |  |  |        |     +--rw node-id       te-node-id
             |  |  |        |     +--rw hop-type?     te-hop-type
             |  |  |        |     +--rw direction?    te-link-direction
             |  |  |        +--:(as-number)
             |  |  |        |  +--rw as-number-hop
             |  |  |        |     +--rw as-number    inet:as-number
             |  |  |        |     +--rw hop-type?    te-hop-type
             |  |  |        +--:(label)
             |  |  |           +--rw label-hop
             |  |  |              +--rw te-label
             |  |  |                 +--rw (technology)?
             |  |  |                 |  +--:(generic)
             |  |  |                 |     +--rw generic?
             |  |  |                 |             rt-types:generalized-label
             |  |  |                 +--rw direction?
             |  |  |                         te-label-direction
             |  |  +--rw backup-path* [index]
             |  |  |  +--rw index           uint32
             |  |  |  +--rw network-ref?
             |  |  |  |       -> /nw:networks/network/network-id
             |  |  |  +--rw path-element* [path-element-id]
             |  |  |     +--rw path-element-id              uint32
             |  |  |     +--rw (type)?
             |  |  |        +--:(numbered-node-hop)
             |  |  |        |  +--rw numbered-node-hop
             |  |  |        |     +--rw node-id     te-node-id
             |  |  |        |     +--rw hop-type?   te-hop-type
             |  |  |        +--:(numbered-link-hop)
             |  |  |        |  +--rw numbered-link-hop
             |  |  |        |     +--rw link-tp-id    te-tp-id
             |  |  |        |     +--rw hop-type?     te-hop-type
             |  |  |        |     +--rw direction?    te-link-direction
             |  |  |        +--:(unnumbered-link-hop)
             |  |  |        |  +--rw unnumbered-link-hop
             |  |  |        |     +--rw link-tp-id    te-tp-id
             |  |  |        |     +--rw node-id       te-node-id
             |  |  |        |     +--rw hop-type?     te-hop-type
             |  |  |        |     +--rw direction?    te-link-direction
             |  |  |        +--:(as-number)
             |  |  |        |  +--rw as-number-hop
             |  |  |        |     +--rw as-number    inet:as-number
             |  |  |        |     +--rw hop-type?    te-hop-type
             |  |  |        +--:(label)
             |  |  |           +--rw label-hop
             |  |  |              +--rw te-label
             |  |  |                 +--rw (technology)?
             |  |  |                 |  +--:(generic)
             |  |  |                 |     +--rw generic?
             |  |  |                 |             rt-types:generalized-label
             |  |  |                 +--rw direction?
             |  |  |                         te-label-direction
             |  |  +--rw protection-type?             identityref
             |  |  +--rw tunnel-termination-points
             |  |  |  +--rw source?        binary
             |  |  |  +--rw destination?   binary
             |  |  +--rw tunnels
             |  |     +--rw sharing?   boolean
             |  |     +--rw tunnel* [tunnel-name]
             |  |        +--rw tunnel-name    string
             |  |        +--rw sharing?       boolean
             |  +--rw path-constraints
             |  |  +--rw te-bandwidth
             |  |  |  +--rw (technology)?
             |  |  |     +--:(generic)
             |  |  |        +--rw generic?   te-bandwidth
             |  |  +--rw link-protection?          identityref
             |  |  +--rw setup-priority?           uint8
             |  |  +--rw hold-priority?            uint8
             |  |  +--rw signaling-type?           identityref
             |  |  +--rw path-metric-bounds
             |  |  |  +--rw path-metric-bound* [metric-type]
             |  |  |     +--rw metric-type    identityref
             |  |  |     +--rw upper-bound?   uint64
             |  |  +--rw path-affinities-values
             |  |  |  +--rw path-affinities-value* [usage]
             |  |  |     +--rw usage    identityref
             |  |  |     +--rw value?   admin-groups
             |  |  +--rw path-affinity-names
             |  |  |  +--rw path-affinity-name* [usage]
             |  |  |     +--rw usage            identityref
             |  |  |     +--rw affinity-name* [name]
             |  |  |        +--rw name    string
             |  |  +--rw path-srlgs-lists
             |  |  |  +--rw path-srlgs-list* [usage]
             |  |  |     +--rw usage     identityref
             |  |  |     +--rw values*   srlg
             |  |  +--rw path-srlgs-names
             |  |  |  +--rw path-srlgs-name* [usage]
             |  |  |     +--rw usage    identityref
             |  |  |     +--rw names*   string
             |  |  +--rw disjointness?             te-path-disjointness
             |  +--rw optimizations
             |  |  +--rw (algorithm)?
             |  |     +--:(metric) {path-optimization-metric}?
             |  |     |  +--rw optimization-metric* [metric-type]
             |  |     |  |  +--rw metric-type
             |  |     |  |  |       identityref
             |  |     |  |  +--rw weight?
             |  |     |  |  |       uint8
             |  |     |  |  +--rw explicit-route-exclude-objects
             |  |     |  |  |  +--rw route-object-exclude-object*
             |  |     |  |  |          [index]
             |  |     |  |  |     +--rw index
             |  |     |  |  |     |       uint32
             |  |     |  |  |     +--rw (type)?
             |  |     |  |  |        +--:(numbered-node-hop)
             |  |     |  |  |        |  +--rw numbered-node-hop
             |  |     |  |  |        |     +--rw node-id     te-node-id
             |  |     |  |  |        |     +--rw hop-type?   te-hop-type
             |  |     |  |  |        +--:(numbered-link-hop)
             |  |     |  |  |        |  +--rw numbered-link-hop
             |  |     |  |  |        |     +--rw link-tp-id    te-tp-id
             |  |     |  |  |        |     +--rw hop-type?
             |  |     |  |  |        |     |       te-hop-type
             |  |     |  |  |        |     +--rw direction?
             |  |     |  |  |        |             te-link-direction
             |  |     |  |  |        +--:(unnumbered-link-hop)
             |  |     |  |  |        |  +--rw unnumbered-link-hop
             |  |     |  |  |        |     +--rw link-tp-id    te-tp-id
             |  |     |  |  |        |     +--rw node-id
             |  |     |  |  |        |     |       te-node-id
             |  |     |  |  |        |     +--rw hop-type?
             |  |     |  |  |        |     |       te-hop-type
             |  |     |  |  |        |     +--rw direction?
             |  |     |  |  |        |             te-link-direction
             |  |     |  |  |        +--:(as-number)
             |  |     |  |  |        |  +--rw as-number-hop
             |  |     |  |  |        |     +--rw as-number
             |  |     |  |  |        |     |       inet:as-number
             |  |     |  |  |        |     +--rw hop-type?
             |  |     |  |  |        |             te-hop-type
             |  |     |  |  |        +--:(label)
             |  |     |  |  |        |  +--rw label-hop
             |  |     |  |  |        |     +--rw te-label
             |  |     |  |  |        |        +--rw (technology)?
             |  |     |  |  |        |        |  +--:(generic)
             |  |     |  |  |        |        |     +--rw generic?
             |  |     |  |  |        |        |             rt-types:generalized-label
             |  |     |  |  |        |        +--rw direction?
             |  |     |  |  |        |                te-label-direction
             |  |     |  |  |        +--:(srlg)
             |  |     |  |  |           +--rw srlg
             |  |     |  |  |              +--rw srlg?   uint32
             |  |     |  |  +--rw explicit-route-include-objects
             |  |     |  |     +--rw route-object-include-object*
             |  |     |  |             [index]
             |  |     |  |        +--rw index
             |  |     |  |        |       uint32
             |  |     |  |        +--rw (type)?
             |  |     |  |           +--:(numbered-node-hop)
             |  |     |  |           |  +--rw numbered-node-hop
             |  |     |  |           |     +--rw node-id     te-node-id
             |  |     |  |           |     +--rw hop-type?   te-hop-type
             |  |     |  |           +--:(numbered-link-hop)
             |  |     |  |           |  +--rw numbered-link-hop
             |  |     |  |           |     +--rw link-tp-id    te-tp-id
             |  |     |  |           |     +--rw hop-type?
             |  |     |  |           |     |       te-hop-type
             |  |     |  |           |     +--rw direction?
             |  |     |  |           |             te-link-direction
             |  |     |  |           +--:(unnumbered-link-hop)
             |  |     |  |           |  +--rw unnumbered-link-hop
             |  |     |  |           |     +--rw link-tp-id    te-tp-id
             |  |     |  |           |     +--rw node-id
             |  |     |  |           |     |       te-node-id
             |  |     |  |           |     +--rw hop-type?
             |  |     |  |           |     |       te-hop-type
             |  |     |  |           |     +--rw direction?
             |  |     |  |           |             te-link-direction
             |  |     |  |           +--:(as-number)
             |  |     |  |           |  +--rw as-number-hop
             |  |     |  |           |     +--rw as-number
             |  |     |  |           |     |       inet:as-number
             |  |     |  |           |     +--rw hop-type?
             |  |     |  |           |             te-hop-type
             |  |     |  |           +--:(label)
             |  |     |  |              +--rw label-hop
             |  |     |  |                 +--rw te-label
             |  |     |  |                    +--rw (technology)?
             |  |     |  |                    |  +--:(generic)
             |  |     |  |                    |     +--rw generic?
             |  |     |  |                    |             rt-types:generalized-label
             |  |     |  |                    +--rw direction?
             |  |     |  |                            te-label-direction
             |  |     |  +--rw tiebreakers
             |  |     |     +--rw tiebreaker* [tiebreaker-type]
             |  |     |        +--rw tiebreaker-type    identityref
             |  |     +--:(objective-function)
             |  |              {path-optimization-objective-function}?
             |  |        +--rw objective-function
             |  |           +--rw objective-function-type?   identityref
             |  +--ro path-properties
             |  |  +--ro path-metric* [metric-type]
             |  |  |  +--ro metric-type           identityref
             |  |  |  +--ro accumulative-value?   uint64
             |  |  +--ro path-affinities-values
             |  |  |  +--ro path-affinities-value* [usage]
             |  |  |     +--ro usage    identityref
             |  |  |     +--ro value?   admin-groups
             |  |  +--ro path-affinity-names
             |  |  |  +--ro path-affinity-name* [usage]
             |  |  |     +--ro usage            identityref
             |  |  |     +--ro affinity-name* [name]
             |  |  |        +--ro name    string
             |  |  +--ro path-srlgs-lists
             |  |  |  +--ro path-srlgs-list* [usage]
             |  |  |     +--ro usage     identityref
             |  |  |     +--ro values*   srlg
             |  |  +--ro path-srlgs-names
             |  |  |  +--ro path-srlgs-name* [usage]
             |  |  |     +--ro usage    identityref
             |  |  |     +--ro names*   string
             |  |  +--ro path-route-objects
             |  |     +--ro path-route-object* [index]
             |  |        +--ro index                        uint32
             |  |        +--ro (type)?
             |  |           +--:(numbered-node-hop)
             |  |           |  +--ro numbered-node-hop
             |  |           |     +--ro node-id     te-node-id
             |  |           |     +--ro hop-type?   te-hop-type
             |  |           +--:(numbered-link-hop)
             |  |           |  +--ro numbered-link-hop
             |  |           |     +--ro link-tp-id    te-tp-id
             |  |           |     +--ro hop-type?     te-hop-type
             |  |           |     +--ro direction?    te-link-direction
             |  |           +--:(unnumbered-link-hop)
             |  |           |  +--ro unnumbered-link-hop
             |  |           |     +--ro link-tp-id    te-tp-id
             |  |           |     +--ro node-id       te-node-id
             |  |           |     +--ro hop-type?     te-hop-type
             |  |           |     +--ro direction?    te-link-direction
             |  |           +--:(as-number)
             |  |           |  +--ro as-number-hop
             |  |           |     +--ro as-number    inet:as-number
             |  |           |     +--ro hop-type?    te-hop-type
             |  |           +--:(label)
             |  |              +--ro label-hop
             |  |                 +--ro te-label
             |  |                    +--ro (technology)?
             |  |                    |  +--:(generic)
             |  |                    |     +--ro generic?
             |  |                    |             rt-types:generalized-label
             |  |                    +--ro direction?
             |  |                            te-label-direction
             |  +--rw local-link-connectivity* [link-tp-ref]
             |     +--rw link-tp-ref
             |     |       -> ../../../../../nt:termination-point/tp-id
             |     +--rw label-restrictions
             |     |  +--rw label-restriction* [index]
             |     |     +--rw restriction?    enumeration
             |     |     +--rw index           uint32
             |     |     +--rw label-start
             |     |     |  +--rw te-label
             |     |     |     +--rw (technology)?
             |     |     |     |  +--:(generic)
             |     |     |     |     +--rw generic?
             |     |     |     |             rt-types:generalized-label
             |     |     |     +--rw direction?       te-label-direction
             |     |     +--rw label-end
             |     |     |  +--rw te-label
             |     |     |     +--rw (technology)?
             |     |     |     |  +--:(generic)
             |     |     |     |     +--rw generic?
             |     |     |     |             rt-types:generalized-label
             |     |     |     +--rw direction?       te-label-direction
             |     |     +--rw label-step
             |     |     |  +--rw (technology)?
             |     |     |     +--:(generic)
             |     |     |        +--rw generic?   int32
             |     |     +--rw range-bitmap?   yang:hex-string
             |     +--rw is-allowed?           boolean
             |     +--rw underlay {te-topology-hierarchy}?
             |     |  +--rw enabled?                     boolean
             |     |  +--rw primary-path
             |     |  |  +--rw network-ref?
             |     |  |  |       -> /nw:networks/network/network-id
             |     |  |  +--rw path-element* [path-element-id]
             |     |  |     +--rw path-element-id              uint32
             |     |  |     +--rw (type)?
             |     |  |        +--:(numbered-node-hop)
             |     |  |        |  +--rw numbered-node-hop
             |     |  |        |     +--rw node-id     te-node-id
             |     |  |        |     +--rw hop-type?   te-hop-type
             |     |  |        +--:(numbered-link-hop)
             |     |  |        |  +--rw numbered-link-hop
             |     |  |        |     +--rw link-tp-id    te-tp-id
             |     |  |        |     +--rw hop-type?     te-hop-type
             |     |  |        |     +--rw direction?
             |     |  |        |             te-link-direction
             |     |  |        +--:(unnumbered-link-hop)
             |     |  |        |  +--rw unnumbered-link-hop
             |     |  |        |     +--rw link-tp-id    te-tp-id
             |     |  |        |     +--rw node-id       te-node-id
             |     |  |        |     +--rw hop-type?     te-hop-type
             |     |  |        |     +--rw direction?
             |     |  |        |             te-link-direction
             |     |  |        +--:(as-number)
             |     |  |        |  +--rw as-number-hop
             |     |  |        |     +--rw as-number    inet:as-number
             |     |  |        |     +--rw hop-type?    te-hop-type
             |     |  |        +--:(label)
             |     |  |           +--rw label-hop
             |     |  |              +--rw te-label
             |     |  |                 +--rw (technology)?
             |     |  |                 |  +--:(generic)
             |     |  |                 |     +--rw generic?
             |     |  |                 |             rt-types:generalized-label
             |     |  |                 +--rw direction?
             |     |  |                         te-label-direction
             |     |  +--rw backup-path* [index]
             |     |  |  +--rw index           uint32
             |     |  |  +--rw network-ref?
             |     |  |  |       -> /nw:networks/network/network-id
             |     |  |  +--rw path-element* [path-element-id]
             |     |  |     +--rw path-element-id              uint32
             |     |  |     +--rw (type)?
             |     |  |        +--:(numbered-node-hop)
             |     |  |        |  +--rw numbered-node-hop
             |     |  |        |     +--rw node-id     te-node-id
             |     |  |        |     +--rw hop-type?   te-hop-type
             |     |  |        +--:(numbered-link-hop)
             |     |  |        |  +--rw numbered-link-hop
             |     |  |        |     +--rw link-tp-id    te-tp-id
             |     |  |        |     +--rw hop-type?     te-hop-type
             |     |  |        |     +--rw direction?
             |     |  |        |             te-link-direction
             |     |  |        +--:(unnumbered-link-hop)
             |     |  |        |  +--rw unnumbered-link-hop
             |     |  |        |     +--rw link-tp-id    te-tp-id
             |     |  |        |     +--rw node-id       te-node-id
             |     |  |        |     +--rw hop-type?     te-hop-type
             |     |  |        |     +--rw direction?
             |     |  |        |             te-link-direction
             |     |  |        +--:(as-number)
             |     |  |        |  +--rw as-number-hop
             |     |  |        |     +--rw as-number    inet:as-number
             |     |  |        |     +--rw hop-type?    te-hop-type
             |     |  |        +--:(label)
             |     |  |           +--rw label-hop
             |     |  |              +--rw te-label
             |     |  |                 +--rw (technology)?
             |     |  |                 |  +--:(generic)
             |     |  |                 |     +--rw generic?
             |     |  |                 |             rt-types:generalized-label
             |     |  |                 +--rw direction?
             |     |  |                         te-label-direction
             |     |  +--rw protection-type?             identityref
             |     |  +--rw tunnel-termination-points
             |     |  |  +--rw source?        binary
             |     |  |  +--rw destination?   binary
             |     |  +--rw tunnels
             |     |     +--rw sharing?   boolean
             |     |     +--rw tunnel* [tunnel-name]
             |     |        +--rw tunnel-name    string
             |     |        +--rw sharing?       boolean
             |     +--rw path-constraints
             |     |  +--rw te-bandwidth
             |     |  |  +--rw (technology)?
             |     |  |     +--:(generic)
             |     |  |        +--rw generic?   te-bandwidth
             |     |  +--rw link-protection?          identityref
             |     |  +--rw setup-priority?           uint8
             |     |  +--rw hold-priority?            uint8
             |     |  +--rw signaling-type?           identityref
             |     |  +--rw path-metric-bounds
             |     |  |  +--rw path-metric-bound* [metric-type]
             |     |  |     +--rw metric-type    identityref
             |     |  |     +--rw upper-bound?   uint64
             |     |  +--rw path-affinities-values
             |     |  |  +--rw path-affinities-value* [usage]
             |     |  |     +--rw usage    identityref
             |     |  |     +--rw value?   admin-groups
             |     |  +--rw path-affinity-names
             |     |  |  +--rw path-affinity-name* [usage]
             |     |  |     +--rw usage            identityref
             |     |  |     +--rw affinity-name* [name]
             |     |  |        +--rw name    string
             |     |  +--rw path-srlgs-lists
             |     |  |  +--rw path-srlgs-list* [usage]
             |     |  |     +--rw usage     identityref
             |     |  |     +--rw values*   srlg
             |     |  +--rw path-srlgs-names
             |     |  |  +--rw path-srlgs-name* [usage]
             |     |  |     +--rw usage    identityref
             |     |  |     +--rw names*   string
             |     |  +--rw disjointness?
             |     |          te-path-disjointness
             |     +--rw optimizations
             |     |  +--rw (algorithm)?
             |     |     +--:(metric) {path-optimization-metric}?
             |     |     |  +--rw optimization-metric* [metric-type]
             |     |     |  |  +--rw metric-type
             |     |     |  |  |       identityref
             |     |     |  |  +--rw weight?
             |     |     |  |  |       uint8
             |     |     |  |  +--rw explicit-route-exclude-objects
             |     |     |  |  |  +--rw route-object-exclude-object*
             |     |     |  |  |          [index]
             |     |     |  |  |     +--rw index
             |     |     |  |  |     |       uint32
             |     |     |  |  |     +--rw (type)?
             |     |     |  |  |        +--:(numbered-node-hop)
             |     |     |  |  |        |  +--rw numbered-node-hop
             |     |     |  |  |        |     +--rw node-id
             |     |     |  |  |        |     |       te-node-id
             |     |     |  |  |        |     +--rw hop-type?
             |     |     |  |  |        |             te-hop-type
             |     |     |  |  |        +--:(numbered-link-hop)
             |     |     |  |  |        |  +--rw numbered-link-hop
             |     |     |  |  |        |     +--rw link-tp-id
             |     |     |  |  |        |     |       te-tp-id
             |     |     |  |  |        |     +--rw hop-type?
             |     |     |  |  |        |     |       te-hop-type
             |     |     |  |  |        |     +--rw direction?
             |     |     |  |  |        |             te-link-direction
             |     |     |  |  |        +--:(unnumbered-link-hop)
             |     |     |  |  |        |  +--rw unnumbered-link-hop
             |     |     |  |  |        |     +--rw link-tp-id
             |     |     |  |  |        |     |       te-tp-id
             |     |     |  |  |        |     +--rw node-id
             |     |     |  |  |        |     |       te-node-id
             |     |     |  |  |        |     +--rw hop-type?
             |     |     |  |  |        |     |       te-hop-type
             |     |     |  |  |        |     +--rw direction?
             |     |     |  |  |        |             te-link-direction
             |     |     |  |  |        +--:(as-number)
             |     |     |  |  |        |  +--rw as-number-hop
             |     |     |  |  |        |     +--rw as-number
             |     |     |  |  |        |     |       inet:as-number
             |     |     |  |  |        |     +--rw hop-type?
             |     |     |  |  |        |             te-hop-type
             |     |     |  |  |        +--:(label)
             |     |     |  |  |        |  +--rw label-hop
             |     |     |  |  |        |     +--rw te-label
             |     |     |  |  |        |        +--rw (technology)?
             |     |     |  |  |        |        |  +--:(generic)
             |     |     |  |  |        |        |     +--rw generic?
             |     |     |  |  |        |        |             rt-types:generalized-label
             |     |     |  |  |        |        +--rw direction?
             |     |     |  |  |        |                te-label-direction
             |     |     |  |  |        +--:(srlg)
             |     |     |  |  |           +--rw srlg
             |     |     |  |  |              +--rw srlg?   uint32
             |     |     |  |  +--rw explicit-route-include-objects
             |     |     |  |     +--rw route-object-include-object*
             |     |     |  |             [index]
             |     |     |  |        +--rw index
             |     |     |  |        |       uint32
             |     |     |  |        +--rw (type)?
             |     |     |  |           +--:(numbered-node-hop)
             |     |     |  |           |  +--rw numbered-node-hop
             |     |     |  |           |     +--rw node-id
             |     |     |  |           |     |       te-node-id
             |     |     |  |           |     +--rw hop-type?
             |     |     |  |           |             te-hop-type
             |     |     |  |           +--:(numbered-link-hop)
             |     |     |  |           |  +--rw numbered-link-hop
             |     |     |  |           |     +--rw link-tp-id
             |     |     |  |           |     |       te-tp-id
             |     |     |  |           |     +--rw hop-type?
             |     |     |  |           |     |       te-hop-type
             |     |     |  |           |     +--rw direction?
             |     |     |  |           |             te-link-direction
             |     |     |  |           +--:(unnumbered-link-hop)
             |     |     |  |           |  +--rw unnumbered-link-hop
             |     |     |  |           |     +--rw link-tp-id
             |     |     |  |           |     |       te-tp-id
             |     |     |  |           |     +--rw node-id
             |     |     |  |           |     |       te-node-id
             |     |     |  |           |     +--rw hop-type?
             |     |     |  |           |     |       te-hop-type
             |     |     |  |           |     +--rw direction?
             |     |     |  |           |             te-link-direction
             |     |     |  |           +--:(as-number)
             |     |     |  |           |  +--rw as-number-hop
             |     |     |  |           |     +--rw as-number
             |     |     |  |           |     |       inet:as-number
             |     |     |  |           |     +--rw hop-type?
             |     |     |  |           |             te-hop-type
             |     |     |  |           +--:(label)
             |     |     |  |              +--rw label-hop
             |     |     |  |                 +--rw te-label
             |     |     |  |                    +--rw (technology)?
             |     |     |  |                    |  +--:(generic)
             |     |     |  |                    |     +--rw generic?
             |     |     |  |                    |             rt-types:generalized-label
             |     |     |  |                    +--rw direction?
             |     |     |  |                            te-label-direction
             |     |     |  +--rw tiebreakers
             |     |     |     +--rw tiebreaker* [tiebreaker-type]
             |     |     |        +--rw tiebreaker-type    identityref
             |     |     +--:(objective-function)
             |     |              {path-optimization-objective-function}?
             |     |        +--rw objective-function
             |     |           +--rw objective-function-type?
             |     |                   identityref
             |     +--ro path-properties
             |        +--ro path-metric* [metric-type]
             |        |  +--ro metric-type           identityref
             |        |  +--ro accumulative-value?   uint64
             |        +--ro path-affinities-values
             |        |  +--ro path-affinities-value* [usage]
             |        |     +--ro usage    identityref
             |        |     +--ro value?   admin-groups
             |        +--ro path-affinity-names
             |        |  +--ro path-affinity-name* [usage]
             |        |     +--ro usage            identityref
             |        |     +--ro affinity-name* [name]
             |        |        +--ro name    string
             |        +--ro path-srlgs-lists
             |        |  +--ro path-srlgs-list* [usage]
             |        |     +--ro usage     identityref
             |        |     +--ro values*   srlg
             |        +--ro path-srlgs-names
             |        |  +--ro path-srlgs-name* [usage]
             |        |     +--ro usage    identityref
             |        |     +--ro names*   string
             |        +--ro path-route-objects
             |           +--ro path-route-object* [index]
             |              +--ro index                        uint32
             |              +--ro (type)?
             |                 +--:(numbered-node-hop)
             |                 |  +--ro numbered-node-hop
             |                 |     +--ro node-id     te-node-id
             |                 |     +--ro hop-type?   te-hop-type
             |                 +--:(numbered-link-hop)
             |                 |  +--ro numbered-link-hop
             |                 |     +--ro link-tp-id    te-tp-id
             |                 |     +--ro hop-type?     te-hop-type
             |                 |     +--ro direction?
             |                 |             te-link-direction
             |                 +--:(unnumbered-link-hop)
             |                 |  +--ro unnumbered-link-hop
             |                 |     +--ro link-tp-id    te-tp-id
             |                 |     +--ro node-id       te-node-id
             |                 |     +--ro hop-type?     te-hop-type
             |                 |     +--ro direction?
             |                 |             te-link-direction
             |                 +--:(as-number)
             |                 |  +--ro as-number-hop
             |                 |     +--ro as-number    inet:as-number
             |                 |     +--ro hop-type?    te-hop-type
             |                 +--:(label)
             |                    +--ro label-hop
             |                       +--ro te-label
             |                          +--ro (technology)?
             |                          |  +--:(generic)
             |                          |     +--ro generic?
             |                          |             rt-types:generalized-label
             |                          +--ro direction?
             |                                  te-label-direction
             +--ro oper-status?
             |       te-types:te-oper-status
             +--ro geolocation
             |  +--ro altitude?    int64
             |  +--ro latitude?    geographic-coordinate-degree
             |  +--ro longitude?   geographic-coordinate-degree
             +--ro statistics
             |  +--ro discontinuity-time?         yang:date-and-time
             |  +--ro tunnel-termination-point
             |  |  +--ro disables?             yang:counter32
             |  |  +--ro enables?              yang:counter32
             |  |  +--ro maintenance-clears?   yang:counter32
             |  |  +--ro maintenance-sets?     yang:counter32
             |  |  +--ro modifies?             yang:counter32
             |  |  +--ro downs?                yang:counter32
             |  |  +--ro ups?                  yang:counter32
             |  |  +--ro in-service-clears?    yang:counter32
             |  |  +--ro in-service-sets?      yang:counter32
             |  +--ro local-link-connectivity
             |     +--ro creates?    yang:counter32
             |     +--ro deletes?    yang:counter32
             |     +--ro disables?   yang:counter32
             |     +--ro enables?    yang:counter32
             |     +--ro modifies?   yang:counter32
             +--rw supporting-tunnel-termination-point*
                     [node-ref tunnel-tp-ref]
                +--rw node-ref         inet:uri
                +--rw tunnel-tp-ref    binary
     augment /nw:networks/nw:network/nt:link:
       +--rw te!
          +--rw (bundle-stack-level)?
          |  +--:(bundle)
          |  |  +--rw bundled-links
          |  |     +--rw bundled-link* [sequence]
          |  |        +--rw sequence      uint32
          |  |        +--rw src-tp-ref?   leafref
          |  |        +--rw des-tp-ref?   leafref
          |  +--:(component)
          |     +--rw component-links
          |        +--rw component-link* [sequence]
          |           +--rw sequence             uint32
          |           +--rw src-interface-ref?   string
          |           +--rw des-interface-ref?   string
          +--rw te-link-template*
          |       -> ../../../../te/templates/link-template/name
          |       {template}?
          +--rw te-link-attributes
          |  +--rw access-type?
          |  |       te-types:te-link-access-type
          |  +--rw external-domain
          |  |  +--rw network-ref?
          |  |  |       -> /nw:networks/network/network-id
          |  |  +--rw remote-te-node-id?      te-types:te-node-id
          |  |  +--rw remote-te-link-tp-id?   te-types:te-tp-id
          |  +--rw is-abstract?                      empty
          |  +--rw name?                             string
          |  +--rw underlay {te-topology-hierarchy}?
          |  |  +--rw enabled?                     boolean
          |  |  +--rw primary-path
          |  |  |  +--rw network-ref?
          |  |  |  |       -> /nw:networks/network/network-id
          |  |  |  +--rw path-element* [path-element-id]
          |  |  |     +--rw path-element-id              uint32
          |  |  |     +--rw (type)?
          |  |  |        +--:(numbered-node-hop)
          |  |  |        |  +--rw numbered-node-hop
          |  |  |        |     +--rw node-id     te-node-id
          |  |  |        |     +--rw hop-type?   te-hop-type
          |  |  |        +--:(numbered-link-hop)
          |  |  |        |  +--rw numbered-link-hop
          |  |  |        |     +--rw link-tp-id    te-tp-id
          |  |  |        |     +--rw hop-type?     te-hop-type
          |  |  |        |     +--rw direction?    te-link-direction
          |  |  |        +--:(unnumbered-link-hop)
          |  |  |        |  +--rw unnumbered-link-hop
          |  |  |        |     +--rw link-tp-id    te-tp-id
          |  |  |        |     +--rw node-id       te-node-id
          |  |  |        |     +--rw hop-type?     te-hop-type
          |  |  |        |     +--rw direction?    te-link-direction
          |  |  |        +--:(as-number)
          |  |  |        |  +--rw as-number-hop
          |  |  |        |     +--rw as-number    inet:as-number
          |  |  |        |     +--rw hop-type?    te-hop-type
          |  |  |        +--:(label)
          |  |  |           +--rw label-hop
          |  |  |              +--rw te-label
          |  |  |                 +--rw (technology)?
          |  |  |                 |  +--:(generic)
          |  |  |                 |     +--rw generic?
          |  |  |                 |             rt-types:generalized-label
          |  |  |                 +--rw direction?
          |  |  |                         te-label-direction
          |  |  +--rw backup-path* [index]
          |  |  |  +--rw index           uint32
          |  |  |  +--rw network-ref?
          |  |  |  |       -> /nw:networks/network/network-id
          |  |  |  +--rw path-element* [path-element-id]
          |  |  |     +--rw path-element-id              uint32
          |  |  |     +--rw (type)?
          |  |  |        +--:(numbered-node-hop)
          |  |  |        |  +--rw numbered-node-hop
          |  |  |        |     +--rw node-id     te-node-id
          |  |  |        |     +--rw hop-type?   te-hop-type
          |  |  |        +--:(numbered-link-hop)
          |  |  |        |  +--rw numbered-link-hop
          |  |  |        |     +--rw link-tp-id    te-tp-id
          |  |  |        |     +--rw hop-type?     te-hop-type
          |  |  |        |     +--rw direction?    te-link-direction
          |  |  |        +--:(unnumbered-link-hop)
          |  |  |        |  +--rw unnumbered-link-hop
          |  |  |        |     +--rw link-tp-id    te-tp-id
          |  |  |        |     +--rw node-id       te-node-id
          |  |  |        |     +--rw hop-type?     te-hop-type
          |  |  |        |     +--rw direction?    te-link-direction
          |  |  |        +--:(as-number)
          |  |  |        |  +--rw as-number-hop
          |  |  |        |     +--rw as-number    inet:as-number
          |  |  |        |     +--rw hop-type?    te-hop-type
          |  |  |        +--:(label)
          |  |  |           +--rw label-hop
          |  |  |              +--rw te-label
          |  |  |                 +--rw (technology)?
          |  |  |                 |  +--:(generic)
          |  |  |                 |     +--rw generic?
          |  |  |                 |             rt-types:generalized-label
          |  |  |                 +--rw direction?
          |  |  |                         te-label-direction
          |  |  +--rw protection-type?             identityref
          |  |  +--rw tunnel-termination-points
          |  |  |  +--rw source?        binary
          |  |  |  +--rw destination?   binary
          |  |  +--rw tunnels
          |  |     +--rw sharing?   boolean
          |  |     +--rw tunnel* [tunnel-name]
          |  |        +--rw tunnel-name    string
          |  |        +--rw sharing?       boolean
          |  +--rw admin-status?
          |  |       te-types:te-admin-status
          |  +--rw link-index?                       uint64
          |  +--rw administrative-group?
          |  |       te-types:admin-groups
          |  +--rw interface-switching-capability*
          |  |       [switching-capability encoding]
          |  |  +--rw switching-capability    identityref
          |  |  +--rw encoding                identityref
          |  |  +--rw max-lsp-bandwidth* [priority]
          |  |     +--rw priority        uint8
          |  |     +--rw te-bandwidth
          |  |        +--rw (technology)?
          |  |           +--:(generic)
          |  |              +--rw generic?   te-bandwidth
          |  +--rw label-restrictions
          |  |  +--rw label-restriction* [index]
          |  |     +--rw restriction?    enumeration
          |  |     +--rw index           uint32
          |  |     +--rw label-start
          |  |     |  +--rw te-label
          |  |     |     +--rw (technology)?
          |  |     |     |  +--:(generic)
          |  |     |     |     +--rw generic?
          |  |     |     |             rt-types:generalized-label
          |  |     |     +--rw direction?       te-label-direction
          |  |     +--rw label-end
          |  |     |  +--rw te-label
          |  |     |     +--rw (technology)?
          |  |     |     |  +--:(generic)
          |  |     |     |     +--rw generic?
          |  |     |     |             rt-types:generalized-label
          |  |     |     +--rw direction?       te-label-direction
          |  |     +--rw label-step
          |  |     |  +--rw (technology)?
          |  |     |     +--:(generic)
          |  |     |        +--rw generic?   int32
          |  |     +--rw range-bitmap?   yang:hex-string
          |  +--rw link-protection-type?             identityref
          |  +--rw max-link-bandwidth
          |  |  +--rw te-bandwidth
          |  |     +--rw (technology)?
          |  |        +--:(generic)
          |  |           +--rw generic?   te-bandwidth
          |  +--rw max-resv-link-bandwidth
          |  |  +--rw te-bandwidth
          |  |     +--rw (technology)?
          |  |        +--:(generic)
          |  |           +--rw generic?   te-bandwidth
          |  +--rw unreserved-bandwidth* [priority]
          |  |  +--rw priority        uint8
          |  |  +--rw te-bandwidth
          |  |     +--rw (technology)?
          |  |        +--:(generic)
          |  |           +--rw generic?   te-bandwidth
          |  +--rw te-default-metric?                uint32
          |  +--rw te-delay-metric?                  uint32
          |  +--rw te-igp-metric?                    uint32
          |  +--rw te-srlgs
          |  |  +--rw value*   te-types:srlg
          |  +--rw te-nsrlgs {nsrlg}?
          |     +--rw id*   uint32
          +--ro oper-status?                   te-types:te-oper-status
          +--ro is-transitional?               empty
          +--ro information-source?            te-info-source
          +--ro information-source-instance?   string
          +--ro information-source-state
          |  +--ro credibility-preference?    uint16
          |  +--ro logical-network-element?   string
          |  +--ro network-instance?          string
          |  +--ro topology
          |     +--ro link-ref?      leafref
          |     +--ro network-ref?   -> /nw:networks/network/network-id
          +--ro information-source-entry*
          |       [information-source information-source-instance]
          |  +--ro information-source                te-info-source
          |  +--ro information-source-instance       string
          |  +--ro information-source-state
          |  |  +--ro credibility-preference?    uint16
          |  |  +--ro logical-network-element?   string
          |  |  +--ro network-instance?          string
          |  |  +--ro topology
          |  |     +--ro link-ref?      leafref
          |  |     +--ro network-ref?
          |  |             -> /nw:networks/network/network-id
          |  +--ro link-index?                       uint64
          |  +--ro administrative-group?
          |  |       te-types:admin-groups
          |  +--ro interface-switching-capability*
          |  |       [switching-capability encoding]
          |  |  +--ro switching-capability    identityref
          |  |  +--ro encoding                identityref
          |  |  +--ro max-lsp-bandwidth* [priority]
          |  |     +--ro priority        uint8
          |  |     +--ro te-bandwidth
          |  |        +--ro (technology)?
          |  |           +--:(generic)
          |  |              +--ro generic?   te-bandwidth
          |  +--ro label-restrictions
          |  |  +--ro label-restriction* [index]
          |  |     +--ro restriction?    enumeration
          |  |     +--ro index           uint32
          |  |     +--ro label-start
          |  |     |  +--ro te-label
          |  |     |     +--ro (technology)?
          |  |     |     |  +--:(generic)
          |  |     |     |     +--ro generic?
          |  |     |     |             rt-types:generalized-label
          |  |     |     +--ro direction?       te-label-direction
          |  |     +--ro label-end
          |  |     |  +--ro te-label
          |  |     |     +--ro (technology)?
          |  |     |     |  +--:(generic)
          |  |     |     |     +--ro generic?
          |  |     |     |             rt-types:generalized-label
          |  |     |     +--ro direction?       te-label-direction
          |  |     +--ro label-step
          |  |     |  +--ro (technology)?
          |  |     |     +--:(generic)
          |  |     |        +--ro generic?   int32
          |  |     +--ro range-bitmap?   yang:hex-string
          |  +--ro link-protection-type?             identityref
          |  +--ro max-link-bandwidth
          |  |  +--ro te-bandwidth
          |  |     +--ro (technology)?
          |  |        +--:(generic)
          |  |           +--ro generic?   te-bandwidth
          |  +--ro max-resv-link-bandwidth
          |  |  +--ro te-bandwidth
          |  |     +--ro (technology)?
          |  |        +--:(generic)
          |  |           +--ro generic?   te-bandwidth
          |  +--ro unreserved-bandwidth* [priority]
          |  |  +--ro priority        uint8
          |  |  +--ro te-bandwidth
          |  |     +--ro (technology)?
          |  |        +--:(generic)
          |  |           +--ro generic?   te-bandwidth
          |  +--ro te-default-metric?                uint32
          |  +--ro te-delay-metric?                  uint32
          |  +--ro te-igp-metric?                    uint32
          |  +--ro te-srlgs
          |  |  +--ro value*   te-types:srlg
          |  +--ro te-nsrlgs {nsrlg}?
          |     +--ro id*   uint32
          +--ro recovery
          |  +--ro restoration-status?   te-types:te-recovery-status
          |  +--ro protection-status?    te-types:te-recovery-status
          +--ro underlay {te-topology-hierarchy}?
          |  +--ro dynamic?     boolean
          |  +--ro committed?   boolean
          +--ro statistics
             +--ro discontinuity-time?                yang:date-and-time
             +--ro disables?                          yang:counter32
             +--ro enables?                           yang:counter32
             +--ro maintenance-clears?                yang:counter32
             +--ro maintenance-sets?                  yang:counter32
             +--ro modifies?                          yang:counter32
             +--ro downs?                             yang:counter32
             +--ro ups?                               yang:counter32
             +--ro fault-clears?                      yang:counter32
             +--ro fault-detects?                     yang:counter32
             +--ro protection-switches?               yang:counter32
             +--ro protection-reverts?                yang:counter32
             +--ro restoration-failures?              yang:counter32
             +--ro restoration-starts?                yang:counter32
             +--ro restoration-successes?             yang:counter32
             +--ro restoration-reversion-failures?    yang:counter32
             +--ro restoration-reversion-starts?      yang:counter32
             +--ro restoration-reversion-successes?   yang:counter32
     augment /nw:networks/nw:network/nw:node/nt:termination-point:
       +--rw te-tp-id?   te-types:te-tp-id
       +--rw te!
          +--rw admin-status?
          |       te-types:te-admin-status
          +--rw name?                             string
          +--rw interface-switching-capability*
          |       [switching-capability encoding]
          |  +--rw switching-capability    identityref
          |  +--rw encoding                identityref
          |  +--rw max-lsp-bandwidth* [priority]
          |     +--rw priority        uint8
          |     +--rw te-bandwidth
          |        +--rw (technology)?
          |           +--:(generic)
          |              +--rw generic?   te-bandwidth
          +--rw inter-domain-plug-id?             binary
          +--rw inter-layer-lock-id*              uint32
          +--ro oper-status?
          |       te-types:te-oper-status
          +--ro geolocation
             +--ro altitude?    int64
             +--ro latitude?    geographic-coordinate-degree
             +--ro longitude?   geographic-coordinate-degree

Приложение B. Модель YANG для реализаций без поддержки NMDA

Модуль YANG ietf-te-topology, заданный в разделе 7, предназначен для использования с реализациями, поддерживающими архитектуру хранилищ данных управления сетью (Network Management Datastore Architecture или NMDA), определённую в [RFC8342]. Чтобы модель могли использовать реализации без поддержки NMDA, ниже определён модуль ietf-te-topology-state в качестве модели состояния, отражающей модуль ietf-te-topology. Однако все узлы данных в модели ietf-te-topology-state являются не настраиваемыми, они приведены для представления применённой конфигурации или производных рабочих состояний.

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

Структура модуль ietf-te-topology-state отражает структуру ietf-te-topology, поэтому дерево YANG для модуля ietf-te-topology-state не приведено.

B.1.Модуль YANG для состояния топологии TE

Модуль ссылается на [RFC6001], [RFC8345], [RFC8776].

   <CODE BEGINS> file "ietf-te-topology-state@2020-08-06.yang"
   module ietf-te-topology-state {
     yang-version 1.1;
     namespace "urn:ietf:params:xml:ns:yang:ietf-te-topology-state";
     prefix tet-s;

     import ietf-te-types {
       prefix te-types;
       reference
         "RFC 8776: Common YANG Data Types for Traffic Engineering";
     }
     import ietf-te-topology {
       prefix tet;
       reference
         "RFC 8795: YANG Data Model for Traffic Engineering (TE)
          Topologies";
     }
     import ietf-network-state {
       prefix nw-s;
       reference
         "RFC 8345: A YANG Data Model for Network Topologies";
     }
     import ietf-network-topology-state {
       prefix nt-s;
       reference
         "RFC 8345: A YANG Data Model for Network Topologies";
     }

     organization
       "IETF Traffic Engineering Architecture and Signaling (TEAS)
        Working Group";
     contact
       "WG Web:   <https://datatracker.ietf.org/wg/teas/> 
        WG List:  <mailto:teas@ietf.org> 

        Editor:   Xufeng Liu
                  <mailto:xufeng.liu.ietf@gmail.com> 

        Editor:   Igor Bryskin
                  <mailto:i_bryskin@yahoo.com> 

        Editor:   Vishnu Pavan Beeram
                  <mailto:vbeeram@juniper.net> 

        Editor:   Tarek Saad
                  <mailto:tsaad@juniper.net> 

        Editor:   Himanshu Shah
                  <mailto:hshah@ciena.com> 

        Editor:   Oscar Gonzalez de Dios
                  <mailto:oscar.gonzalezdedios@telefonica.com>"; 
     description
       "Этот модуль YANG задаёт модель состояния топологии TE.

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

        Распространение и использование в исходной или двоичной форме с
        изменениями или без таковых разрешено в соответствии с лицензией
        Simplified BSD, изложенной в разделе 4  IETF Trust's Legal
        Provisions применительно к документам IETF
        (http://trustee.ietf.org/license-info). 

        Эта версия данного модуля YANG является частью RFC 8795, где
        правовые вопросы рассмотрены более полно.";

     revision 2020-08-06 {
       description
         "Исходный выпуск.";
       reference
         "RFC 8795: YANG Data Model for Traffic Engineering (TE)
          Topologies";
     }

     /*
      * Группировки
      */

     grouping te-node-connectivity-matrix-attributes {
       description
         "Ссылки на точку завершения в записи матрицы связности.";
       container from {
         description
           "Ссылка на LTP источника.";
         leaf tp-ref {
           type leafref {
             path "../../../../../../nt-s:termination-point/nt-s:tp-id";
           }
           description
             "Относительная ссылка на точку завершения.";
         }
         uses te-types:label-set-info;
       }
       container to {
         description
           "Ссылка LTP назначения.";
         leaf tp-ref {
           type leafref {
             path "../../../../../../nt-s:termination-point/nt-s:tp-id";
           }
           description
             "Относительная ссылка на точку завершения.";
         }
         uses te-types:label-set-info;
       }
       uses tet:connectivity-matrix-entry-path-attributes;
     }
     // Атрибуты матрицы связности узла TE.

     grouping te-node-tunnel-termination-point-llc-list {
       description
         "Список связности по локальным каналам (LLCL) точки завершения
          туннеля (TTP) на узле TE.";
       list local-link-connectivity {
         key "link-tp-ref";
         description
           "Возможности завершения между TTP и LTP. Эти сведения могут
            служить для расчёта пути туннеля. Дескрипторы настройки
            возможностей (IACD, RFC 6001) на каждом LTP можно вывести
            из этого списка.";
         reference
           "RFC 6001: Generalized MPLS (GMPLS) Protocol Extensions
            for Multi-Layer and Multi-Region Networks (MLN/MRN)";
         leaf link-tp-ref {
           type leafref {
             path "../../../../../nt-s:termination-point/nt-s:tp-id";
           }
           description
             "LTP.";
         }
         uses te-types:label-set-info;
         uses tet:connectivity-matrix-entry-path-attributes;
       }
       // Связность по локальным каналам.
     }
     // Список LLCL точки завершения туннеля на узле TE.

     /*
      * Узлы данных
      */

     augment "/nw-s:networks/nw-s:network/nw-s:network-types" {
       description
         "Новый тип сети для топологии TE.";
       container te-topology {
         presence "Топология TE.";
         description
           "Присутствие указывает тип топологии TE.";
       }
     }

     augment "/nw-s:networks" {
       description
         "Параметры дополнения для топологий TE.";
       uses tet:te-topologies-augment;
     }

     augment "/nw-s:networks/nw-s:network" {
       when 'nw-s:network-types/tet-s:te-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с типом топологии TE.";
       }
       description
         "Параметры конфигурации для топологии TE.";
       uses tet:te-topology-augment;
     }

     augment "/nw-s:networks/nw-s:network/nw-s:node" {
       when '../nw-s:network-types/tet-s:te-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с типом топологии TE.";
       }
       description
         "Параметры конфигурации для TE на уровне узла.";
       leaf te-node-id {
         type te-types:te-node-id;
         description
           "Идентификатор узла в топологии TE. Узел специфичен для
            топологии, к которой он относится.";
       }
       container te {
         must '../te-node-id' {
           description
             "Узел te-node-id является обязательным.";
         }
         must 'count(../nw-s:supporting-node)<=1' {
           description
             "Для узла в топологии TE не может быть более одного 
              поддерживающего узла. При абстрагировании нескольких
              узлов используется поле underlay-topology.";
         }
         presence "Поддержка TE.";
         description
           "Указывает поддержку TE.";
         uses tet:te-node-augment;
       }
     }

     augment "/nw-s:networks/nw-s:network/nt-s:link" {
       when '../nw-s:network-types/tet-s:te-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с типом топологии TE.";
       }
       description
         "Конфигурационные параметры TE на уровне канала.";
       container te {
         must 'count(../nt-s:supporting-link)<=1' {
           description
             "Для канала в топологии TE не может быть более одного
              поддерживающего канала. Если абстрагируется несколько 
              путей, применяется базовый канал.";
         }
         presence "Поддержка TE.";
         description
           "Указывает поддержку TE.";
         uses tet:te-link-augment;
       }
     }

     augment "/nw-s:networks/nw-s:network/nw-s:node/"
           + "nt-s:termination-point" {
       when '../../nw-s:network-types/tet-s:te-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с типом топологии TE.";
       }
       description
         "Конфигурационные параметры TE на уровне точки завершения.";
       uses tet:te-termination-point-augment;
     }

     augment "/nw-s:networks/nw-s:network/nt-s:link/te/"
           + "bundle-stack-level/bundle/bundled-links/bundled-link" {
       when '../../../../nw-s:network-types/tet-s:te-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с типом топологии TE.";
       }
       description
         "Augmentation for a TE bundled link.";
       leaf src-tp-ref {
         type leafref {
           path "../../../../../nw-s:node[nw-s:node-id = "
              + "current()/../../../../nt-s:source/"
              + "nt-s:source-node]/"
              + "nt-s:termination-point/nt-s:tp-id";
           require-instance true;
         }
         description
           "Ссылка на другую точку завершения TE на том же
            узле-источнике.";
       }
       leaf des-tp-ref {
         type leafref {
           path "../../../../../nw-s:node[nw-s:node-id = "
              + "current()/../../../../nt-s:destination/"
              + "nt-s:dest-node]/"
              + "nt-s:termination-point/nt-s:tp-id";
           require-instance true;
         }
         description
           "Ссылка на другую точку завершения TE на том же
            узле-источнике.";
       }
     }

     augment "/nw-s:networks/nw-s:network/nw-s:node/te/"
           + "information-source-entry/connectivity-matrices/"
           + "connectivity-matrix" {
       when '../../../../../nw-s:network-types/tet-s:te-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с типом топологии TE.";
       }
       description
         "Дополнение для матрицы связности узла TE.";
       uses te-node-connectivity-matrix-attributes;
     }

     augment "/nw-s:networks/nw-s:network/nw-s:node/te/"
           + "te-node-attributes/connectivity-matrices/"
           + "connectivity-matrix" {
       when '../../../../../nw-s:network-types/tet-s:te-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с типом топологии TE.";
       }
       description
         "Дополнение для матрицы связности узла TE.";
       uses te-node-connectivity-matrix-attributes;
     }

     augment "/nw-s:networks/nw-s:network/nw-s:node/te/"
           + "tunnel-termination-point/local-link-connectivities" {
       when '../../../../nw-s:network-types/tet-s:te-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с типом топологии TE.";
       }
       description
         "Дополнение для связности узла TE по локальным каналам 
          TTP LLC.";
       uses te-node-tunnel-termination-point-llc-list;
     }
   }
   <CODE ENDS>

Приложение C. Пример для связанного с технологией дополнения

В этом приложении представлен пример модуля YANG, определяющего связанную с технологией модель топологии TE для примера топологии, описанного в разделе 6.

Модуль ссылается на [RFC8345].

   module example-topology {
     yang-version 1.1;
     namespace "https://example.com/example-topology";
     prefix ex-topo;

     import ietf-network {
       prefix nw;
       reference
         "RFC 8345: A YANG Data Model for Network Topologies";
     }
     import ietf-network-topology {
       prefix nt;
       reference
         "RFC 8345: A YANG Data Model for Network Topologies";
     }
     import ietf-te-topology {
       prefix tet;
       reference
         "RFC 8795: YANG Data Model for Traffic Engineering (TE)
          Topologies";
     }

     organization
       "Пример организации";
     contact
       "Editor: Автор примера";
     description
       "Этот модуль определяет модель данных топологии для примера
        технологии.";

     revision 2020-06-29 {
       description
         "Исходный выпуск.";
       reference
         "Ссылка на пример";
     }

     /*
      * Узлы данных
      */

     augment "/nw:networks/nw:network/nw:network-types/"
           + "tet:te-topology" {
       description
         "Дополнение для типов сетей с целью задания типа
          примера топологии.";
       container example-topology {
         presence "Добавляет новый тип сети для примера топологии.";
         description
           "Присутствие указывает тип примера топологии.";
       }
     }

     augment "/nw:networks/nw:network/tet:te" {
       when '../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       description
         "Дополнение для топологии сети.";
       container attributes {
         description
           "Атрибуты для примера технологии.";
         leaf attribute-1 {
           type uint8;
           description
             "Атрибут 1 для примера технологии.";
         }
       }
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:te-node-attributes" {
       when '../../../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       description
         "Дополнение для атрибутов узла.";
       container attributes {
         description
           "Атрибуты для примера технологии.";
         leaf attribute-2 {
           type uint8;
           description
             "Атрибут 2 для примера технологии.";
         }
       }
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:te-node-attributes/tet:connectivity-matrices" {
       when '../../../../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       description
         "Дополнение для матриц связности узла.";
       container attributes {
         description
           "Атрибуты для примера технологии.";
         leaf attribute-3 {
           type uint8;
           description
             "Атрибут 3 для примера технологии.";
         }
       }
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:te-node-attributes/tet:connectivity-matrices/"
           + "tet:connectivity-matrix" {
       when '../../../../../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       description
         "Дополнение для матриц связности узла.";
       container attributes {
         description
           "Атрибуты для примера технологии.";
         leaf attribute-3 {
           type uint8;
           description
             "Атрибут 3 для примера технологии.";
         }
       }
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:tunnel-termination-point" {
       when '../../../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       description
         " Дополнение для TTP.";
       container attributes {
         description
           "Атрибуты для примера технологии.";
         leaf attribute-4 {
           type uint8;
           description
             "Атрибут 4 для примера технологии.";
         }
       }
     }

     augment "/nw:networks/nw:network/nw:node/nt:termination-point/"
           + "tet:te" {
       when '../../../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       description
         "Дополнение для LTP.";
       container attributes {
         description
           "Атрибуты для примера технологии.";
         leaf attribute-5 {
           type uint8;
           description
             "Атрибут 5 для примера технологии.";
         }
       }
     }

     augment "/nw:networks/nw:network/nt:link/tet:te/"
           + "tet:te-link-attributes" {
       when '../../../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       description
         "Дополнение для атрибутов канала.";
       container attributes {
         description
           "Атрибуты для примера технологии.";
         leaf attribute-6 {
           type uint8;
           description
             "Атрибут 6 для примера технологии.";
         }
       }
     }

     /*
      * Дополнения для пропускной способности TE.
      */

     augment "/nw:networks/tet:te/tet:templates/"
           + "tet:link-template/tet:te-link-attributes/"
           + "tet:interface-switching-capability/tet:max-lsp-bandwidth/"
           + "tet:te-bandwidth/tet:technology" {
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf bandwidth-1 {
             type uint32;
             description
               "Пропускная способность 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для пропускной способности TE.";
     }

     augment "/nw:networks/tet:te/tet:templates/"
           + "tet:link-template/tet:te-link-attributes/"
           + "tet:max-link-bandwidth/"
           + "tet:te-bandwidth/tet:technology" {
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf bandwidth-1 {
             type uint32;
             description
               "Пропускная способность 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для пропускной способности TE.";
     }

     augment "/nw:networks/tet:te/tet:templates/"
           + "tet:link-template/tet:te-link-attributes/"
           + "tet:max-resv-link-bandwidth/"
           + "tet:te-bandwidth/tet:technology" {
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf bandwidth-1 {
             type uint32;
             description
               "Пропускная способность 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для пропускной способности TE.";
     }

     augment "/nw:networks/tet:te/tet:templates/"
           + "tet:link-template/tet:te-link-attributes/"
           + "tet:unreserved-bandwidth/"
           + "tet:te-bandwidth/tet:technology" {
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf bandwidth-1 {
             type uint32;
             description
               "Пропускная способность 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для пропускной способности TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:te-node-attributes/tet:connectivity-matrices/"
           + "tet:path-constraints/tet:te-bandwidth/tet:technology" {
       when '../../../../../../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf bandwidth-1 {
             type uint32;
             description
               "Пропускная способность 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для пропускной способности TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:te-node-attributes/tet:connectivity-matrices/"
           + "tet:connectivity-matrix/"
           + "tet:path-constraints/tet:te-bandwidth/tet:technology" {
       when '../../../../../../../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf bandwidth-1 {
             type uint32;
             description
               "Пропускная способность 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для пропускной способности TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:information-source-entry/tet:connectivity-matrices/"
           + "tet:path-constraints/tet:te-bandwidth/tet:technology" {
       when '../../../../../../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf bandwidth-1 {
             type uint32;
             description
               "Пропускная способность 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для пропускной способности TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:information-source-entry/tet:connectivity-matrices/"
           + "tet:connectivity-matrix/"
           + "tet:path-constraints/tet:te-bandwidth/tet:technology" {
       when '../../../../../../../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf bandwidth-1 {
             type uint32;
             description
               "Пропускная способность 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для пропускной способности TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:tunnel-termination-point/"
           + "tet:client-layer-adaptation/tet:switching-capability/"
           + "tet:te-bandwidth/tet:technology" {
       when '../../../../../../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf bandwidth-1 {
             type uint32;
             description
               "Пропускная способность 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для пропускной способности TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:tunnel-termination-point/"
           + "tet:local-link-connectivities/tet:path-constraints/"
           + "tet:te-bandwidth/tet:technology" {
       when '../../../../../../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf bandwidth-1 {
             type uint32;
             description
               "Пропускная способность 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для пропускной способности TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:tunnel-termination-point/"
           + "tet:local-link-connectivities/"
           + "tet:local-link-connectivity/tet:path-constraints/"
           + "tet:te-bandwidth/tet:technology" {
       when '../../../../../../../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf bandwidth-1 {
             type uint32;
             description
               "Пропускная способность 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для пропускной способности TE.";
     }

     augment "/nw:networks/nw:network/nt:link/tet:te/"
           + "tet:te-link-attributes/"
           + "tet:interface-switching-capability/tet:max-lsp-bandwidth/"
           + "tet:te-bandwidth/tet:technology" {
       when '../../../../../../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf bandwidth-1 {
             type uint32;
             description
               "Пропускная способность 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для пропускной способности TE.";
     }

     augment "/nw:networks/nw:network/nt:link/tet:te/"
           + "tet:te-link-attributes/"
           + "tet:max-link-bandwidth/"
           + "tet:te-bandwidth/tet:technology" {
       when '../../../../../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf bandwidth-1 {
             type uint32;
             description
               "Пропускная способность 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для пропускной способности TE.";
     }

     augment "/nw:networks/nw:network/nt:link/tet:te/"
           + "tet:te-link-attributes/"
           + "tet:max-resv-link-bandwidth/"
           + "tet:te-bandwidth/tet:technology" {
       when '../../../../../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf bandwidth-1 {
             type uint32;
             description
               "Пропускная способность 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для пропускной способности TE.";
     }

     augment "/nw:networks/nw:network/nt:link/tet:te/"
           + "tet:information-source-entry/"
           + "tet:interface-switching-capability/tet:max-lsp-bandwidth/"
           + "tet:te-bandwidth/tet:technology" {
       when '../../../../../../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf bandwidth-1 {
             type uint32;
             description
               "Пропускная способность 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для пропускной способности TE.";
     }

     augment "/nw:networks/nw:network/nt:link/tet:te/"
           + "tet:information-source-entry/"
           + "tet:max-link-bandwidth/"
           + "tet:te-bandwidth/tet:technology" {
       when '../../../../../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf bandwidth-1 {
             type uint32;
             description
               "Пропускная способность 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для пропускной способности TE.";
     }

     augment "/nw:networks/nw:network/nt:link/tet:te/"
           + "tet:information-source-entry/"
           + "tet:max-resv-link-bandwidth/"
           + "tet:te-bandwidth/tet:technology" {
       when '../../../../../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf bandwidth-1 {
             type uint32;
             description
               "Пропускная способность 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для пропускной способности TE.";
     }

     augment "/nw:networks/nw:network/nt:link/tet:te/"
           + "tet:information-source-entry/"
           + "tet:unreserved-bandwidth/"
           + "tet:te-bandwidth/tet:technology" {
       when '../../../../../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf bandwidth-1 {
             type uint32;
             description
               "Пропускная способность 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для пропускной способности TE.";
     }

     augment "/nw:networks/nw:network/nw:node/nt:termination-point/"
           + "tet:te/tet:interface-switching-capability/"
           + "tet:max-lsp-bandwidth/tet:te-bandwidth/tet:technology" {
       when '../../../../../../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf bandwidth-1 {
             type uint32;
             description
               "Пропускная способность 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для пропускной способности TE.";
     }

     /*
      * Дополнения для метки TE.
      */

     augment "/nw:networks/tet:te/tet:templates/"
           + "tet:link-template/tet:te-link-attributes/"
           + "tet:underlay/tet:primary-path/tet:path-element/tet:type/"
           + "tet:label/tet:label-hop/tet:te-label/tet:technology" {
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/tet:te/tet:templates/"
           + "tet:link-template/tet:te-link-attributes/"
           + "tet:underlay/tet:backup-path/tet:path-element/tet:type/"
           + "tet:label/tet:label-hop/tet:te-label/tet:technology" {
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/tet:te/tet:templates/"
           + "tet:link-template/tet:te-link-attributes/"
           + "tet:label-restrictions/tet:label-restriction/"
           + "tet:label-start/tet:te-label/tet:technology" {
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/tet:te/tet:templates/"
           + "tet:link-template/tet:te-link-attributes/"
           + "tet:label-restrictions/tet:label-restriction/"
           + "tet:label-end/tet:te-label/tet:technology" {
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     /* Ниже атрибутов и матриц связности узла TE. */

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:te-node-attributes/tet:connectivity-matrices/"
           + "tet:label-restrictions/tet:label-restriction/"
           + "tet:label-start/tet:te-label/tet:technology" {
       when '../../../../../../../../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:te-node-attributes/tet:connectivity-matrices/"
           + "tet:label-restrictions/tet:label-restriction/"
           + "tet:label-end/tet:te-label/tet:technology" {
       when '../../../../../../../../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:te-node-attributes/tet:connectivity-matrices/"
           + "tet:underlay/tet:primary-path/tet:path-element/tet:type/"
           + "tet:label/tet:label-hop/tet:te-label/tet:technology" {
       when '../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:te-node-attributes/tet:connectivity-matrices/"
           + "tet:underlay/tet:backup-path/tet:path-element/tet:type/"
           + "tet:label/tet:label-hop/tet:te-label/tet:technology" {
       when '../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:te-node-attributes/tet:connectivity-matrices/"
           + "tet:path-properties/tet:path-route-objects/"
           + "tet:path-route-object/tet:type/"
           + "tet:label/tet:label-hop/tet:te-label/tet:technology" {
       when '../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     /* Under te-node-attributes/.../connectivity-matrix */

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:te-node-attributes/tet:connectivity-matrices/"
           + "tet:connectivity-matrix/tet:from/tet:label-restrictions/"
           + "tet:label-restriction/tet:label-start/"
           + "tet:te-label/tet:technology" {
       when '../../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:te-node-attributes/tet:connectivity-matrices/"
           + "tet:connectivity-matrix/tet:from/"
           + "tet:label-restrictions/tet:label-restriction/"
           + "tet:label-end/tet:te-label/tet:technology" {
       when '../../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:te-node-attributes/tet:connectivity-matrices/"
           + "tet:connectivity-matrix/tet:to/tet:label-restrictions/"
           + "tet:label-restriction/tet:label-start/"
           + "tet:te-label/tet:technology" {
       when '../../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:te-node-attributes/tet:connectivity-matrices/"
           + "tet:connectivity-matrix/tet:to/"
           + "tet:label-restrictions/tet:label-restriction/"
           + "tet:label-end/tet:te-label/tet:technology" {
       when '../../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:te-node-attributes/tet:connectivity-matrices/"
           + "tet:connectivity-matrix/"
           + "tet:underlay/tet:primary-path/tet:path-element/tet:type/"
           + "tet:label/tet:label-hop/tet:te-label/tet:technology" {
       when '../../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:te-node-attributes/tet:connectivity-matrices/"
           + "tet:connectivity-matrix/"
           + "tet:underlay/tet:backup-path/tet:path-element/tet:type/"
           + "tet:label/tet:label-hop/tet:te-label/tet:technology" {
       when '../../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:te-node-attributes/tet:connectivity-matrices/"
           + "tet:connectivity-matrix/"
           + "tet:path-properties/tet:path-route-objects/"
           + "tet:path-route-object/tet:type/"
           + "tet:label/tet:label-hop/tet:te-label/tet:technology" {
       when '../../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     /* Ниже записи источника инаформации и матриц связности */

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:information-source-entry/tet:connectivity-matrices/"
           + "tet:label-restrictions/tet:label-restriction/"
           + "tet:label-start/tet:te-label/tet:technology" {
       when '../../../../../../../../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:information-source-entry/tet:connectivity-matrices/"
           + "tet:label-restrictions/tet:label-restriction/"
           + "tet:label-end/tet:te-label/tet:technology" {
       when '../../../../../../../../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:information-source-entry/tet:connectivity-matrices/"
           + "tet:underlay/tet:primary-path/tet:path-element/tet:type/"
           + "tet:label/tet:label-hop/tet:te-label/tet:technology" {
       when '../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:information-source-entry/tet:connectivity-matrices/"
           + "tet:underlay/tet:backup-path/tet:path-element/tet:type/"
           + "tet:label/tet:label-hop/tet:te-label/tet:technology" {
       when '../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:information-source-entry/tet:connectivity-matrices/"
           + "tet:path-properties/tet:path-route-objects/"
           + "tet:path-route-object/tet:type/"
           + "tet:label/tet:label-hop/tet:te-label/tet:technology" {
       when '../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     /* Under information-source-entry/.../connectivity-matrix */

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:information-source-entry/tet:connectivity-matrices/"
           + "tet:connectivity-matrix/tet:from/"
           + "tet:label-restrictions/tet:label-restriction/"
           + "tet:label-start/tet:te-label/tet:technology" {
       when '../../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:information-source-entry/tet:connectivity-matrices/"
           + "tet:connectivity-matrix/tet:from/"
           + "tet:label-restrictions/tet:label-restriction/"
           + "tet:label-end/tet:te-label/tet:technology" {
       when '../../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:information-source-entry/tet:connectivity-matrices/"
           + "tet:connectivity-matrix/tet:to/"
           + "tet:label-restrictions/tet:label-restriction/"
           + "tet:label-start/tet:te-label/tet:technology" {
       when '../../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:information-source-entry/tet:connectivity-matrices/"
           + "tet:connectivity-matrix/tet:to/"
           + "tet:label-restrictions/tet:label-restriction/"
           + "tet:label-end/tet:te-label/tet:technology" {
       when '../../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:information-source-entry/tet:connectivity-matrices/"
           + "tet:connectivity-matrix/"
           + "tet:underlay/tet:primary-path/tet:path-element/tet:type/"
           + "tet:label/tet:label-hop/tet:te-label/tet:technology" {
       when '../../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:information-source-entry/tet:connectivity-matrices/"
           + "tet:connectivity-matrix/"
           + "tet:underlay/tet:backup-path/tet:path-element/tet:type/"
           + "tet:label/tet:label-hop/tet:te-label/tet:technology" {
       when '../../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:information-source-entry/tet:connectivity-matrices/"
           + "tet:connectivity-matrix/"
           + "tet:path-properties/tet:path-route-objects/"
           + "tet:path-route-object/tet:type/"
           + "tet:label/tet:label-hop/tet:te-label/tet:technology" {
       when '../../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     /* Ниже точки завершения туннеля и связности локального канала */

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:tunnel-termination-point/"
           + "tet:local-link-connectivities/tet:label-restrictions/"
           + "tet:label-restriction/tet:label-start/tet:te-label/"
           + "tet:technology" {
       when '../../../../../../../../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:tunnel-termination-point/"
           + "tet:local-link-connectivities/tet:label-restrictions/"
           + "tet:label-restriction/tet:label-end/"
           + "tet:te-label/tet:technology" {
       when '../../../../../../../../nw:network-types/tet:te-topology/'
          + 'ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:tunnel-termination-point/"
           + "tet:local-link-connectivities/tet:underlay/"
           + "tet:primary-path/tet:path-element/tet:type/"
           + "tet:label/tet:label-hop/tet:te-label/tet:technology" {
       when '../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:tunnel-termination-point/"
           + "tet:local-link-connectivities/tet:underlay/"
           + "tet:backup-path/tet:path-element/tet:type/"
           + "tet:label/tet:label-hop/tet:te-label/tet:technology" {
       when '../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:tunnel-termination-point/"
           + "tet:local-link-connectivities/tet:path-properties/"
           + "tet:path-route-objects/tet:path-route-object/tet:type/"
           + "tet:label/tet:label-hop/tet:te-label/tet:technology" {
       when '../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     /* Ниже точки завершения туннеля, ..., связности  локального канала */

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:tunnel-termination-point/"
           + "tet:local-link-connectivities/"
           + "tet:local-link-connectivity/tet:label-restrictions/"
           + "tet:label-restriction/tet:label-start/"
           + "tet:te-label/tet:technology" {
       when '../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:tunnel-termination-point/"
           + "tet:local-link-connectivities/"
           + "tet:local-link-connectivity/tet:label-restrictions/"
           + "tet:label-restriction/tet:label-end/"
           + "tet:te-label/tet:technology" {
       when '../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:tunnel-termination-point/"
           + "tet:local-link-connectivities/"
           + "tet:local-link-connectivity/tet:underlay/"
           + "tet:primary-path/tet:path-element/tet:type/"
           + "tet:label/tet:label-hop/tet:te-label/tet:technology" {
       when '../../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:tunnel-termination-point/"
           + "tet:local-link-connectivities/"
           + "tet:local-link-connectivity/tet:underlay/"
           + "tet:backup-path/tet:path-element/tet:type/"
           + "tet:label/tet:label-hop/tet:te-label/tet:technology" {
       when '../../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nw:node/tet:te/"
           + "tet:tunnel-termination-point/"
           + "tet:local-link-connectivities/"
           + "tet:local-link-connectivity/tet:path-properties/"
           + "tet:path-route-objects/tet:path-route-object/tet:type/"
           + "tet:label/tet:label-hop/tet:te-label/tet:technology" {
       when '../../../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     /* Under te-link-attributes */

     augment "/nw:networks/nw:network/nt:link/tet:te/"
           + "tet:te-link-attributes/"
           + "tet:label-restrictions/tet:label-restriction/"
           + "tet:label-start/tet:te-label/tet:technology" {
       when '../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nt:link/tet:te/"
           + "tet:te-link-attributes/tet:label-restrictions/"
           + "tet:label-restriction/tet:label-end/"
           + "tet:te-label/tet:technology" {
       when '../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nt:link/tet:te/"
           + "tet:te-link-attributes/tet:underlay/"
           + "tet:primary-path/tet:path-element/tet:type/"
           + "tet:label/tet:label-hop/tet:te-label/tet:technology" {
       when '../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nt:link/tet:te/"
           + "tet:te-link-attributes/tet:underlay/"
           + "tet:backup-path/tet:path-element/tet:type/"
           + "tet:label/tet:label-hop/tet:te-label/tet:technology" {
       when '../../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     /* Ниже записи источника сведений для канала TE */

     augment "/nw:networks/nw:network/nt:link/tet:te/"
           + "tet:information-source-entry/tet:label-restrictions/"
           + "tet:label-restriction/tet:label-start/"
           + "tet:te-label/tet:technology" {
       when '../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }

     augment "/nw:networks/nw:network/nt:link/tet:te/"
           + "tet:information-source-entry/tet:label-restrictions/"
           + "tet:label-restriction/tet:label-end/"
           + "tet:te-label/tet:technology" {
       when '../../../../../../../nw:network-types/'
          + 'tet:te-topology/ex-topo:example-topology' {
         description
           "Параметры дополнения применяются лишь для сетей
            с примером типа топологии TE.";
       }
       case example {
         container example {
           description
             "Атрибуты для примера технологии.";
           leaf label-1 {
             type uint32;
             description
               "Метка 1 для примера технологии.";
           }
         }
       }
       description
         "Дополнение для метки TE.";
     }
   }

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

Авторы благодарны Lou Berger, Sue Hares, Mazen Khaddam, Cyril Margaria, Zafar Ali за дискуссии по разработке и полезные предложения.

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

Sergio Belotti
Nokia
Email: sergio.belotti@nokia.com
 
Dieter Beller
Nokia
Email: Dieter.Beller@nokia.com
 
Carlo Perocchio
Ericsson
Email: carlo.perocchio@ericsson.com
 
Italo Busi
Huawei Technologies
Email: Italo.Busi@huawei.com

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

Xufeng Liu
Volta Networks
Email: xufeng.liu.ietf@gmail.com
 
Igor Bryskin
Futurewei Technologies, Inc.
Email: i_bryskin@yahoo.com
 
Vishnu Pavan Beeram
Juniper Networks
Email: vbeeram@juniper.net
 
Tarek Saad
Juniper Networks
Email: tsaad@juniper.net
 
Himanshu Shah
Ciena
Email: hshah@ciena.com
 
Oscar Gonzalez de Dios
Telefonica
Email: oscar.gonzalezdedios@telefonica.com

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

nmalykh@protokols.ru


1Internet Engineering Task Force — комиссия по решению инженерных задач Internet.

2Internet Engineering Steering Group — комиссия по инженерным разработкам Internet.

3Shared Risk Link Group — группа общего риска.

4Wavelength Division Multiplexing — мультиплексирование по длине волны.

5Border Gateway Protocol — Link State — протокол граничного шлюза — состояние канала.

6XML Path Language — язык путей XML.

7Опубликован в RFC 9094. Прим. перев.

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

RFC 8808 A YANG Data Model for Factory Default Settings

Internet Engineering Task Force (IETF)                             Q. Wu
Request for Comments: 8808                                        Huawei
Category: Standards Track                                     B. Lengyel
ISSN: 2070-1721                                         Ericsson Hungary
                                                                  Y. Niu
                                                                  Huawei
                                                             August 2020

A YANG Data Model for Factory Default Settings

Модель данных YANG для заводских установок

PDF

Аннотация

Этот документ задаёт модель данных YANG для вызова RPC factory-reset, позволяющего клиентам сбросить сервер к заводским настройкам, заданным по умолчанию. Модуль также определяет необязательное хранилище factory-default, позволяющее клиентам считывать с устройства принятые по умолчанию заводские настройки.

Модель данных YANG в этом документе соответствует архитектуре хранилищ данных управления сетью (Network Management Datastore Architecture или NMDA), определённой в RFC 8342.

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

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

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

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

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

Copyright (c) 2020. Авторские права принадлежат 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 и связанный с ней механизм для сброса сервера к заводским настройкам. Этот механизм может применяться, например, при наличии в имеющейся конфигурации серьёзных ошибок, когда лучшим решением является «настройка с нуля» (factory default).

Вызов удалённой процедуры (remote procedure call или RPC) factory-reset определён в модели данных YANG. При сбросе устройства все предыдущие настройки теряются с заменой установленными на заводе параметрами.

Кроме того, в модули YANG определено необязательное хранилище factory-default с доступом лишь для чтения. Это хранилище содержит данные для замены содержимого доступных для чтения и записи традиционных хранилищ конфигурации при сбросе устройства и может использоваться также в операции <get-data>.

Модель данных YANG в этом документе соответствует архитектуре NMDA, определённой в RFC 8342.

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

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

Перечисленные ниже термины определены в [RFC8342], [RFC7950] и не переопределяются здесь.

  • server — сервер;
  • startup configuration datastore — хранилище стартовой конфигурации;
  • candidate configuration datastore — хранилище будущей конфигурации, хранилище-кандидат;
  • running configuration datastore — хранилище рабочей конфигурации;
  • intended configuration datastore — хранилище предполагаемой конфигурации;
  • operational state datastore — хранилище рабочего состояния;
  • conventional configuration datastore — традиционное (обычное) хранилище данных конфигурации;
  • datastore schema — схема хранилища данных;
  • RPC operation — операция RPC.

Этот документ определяет один термин.

factory-default datastore — хранилище заводский настроек

Доступное лишь для чтения хранилище данных конфигурации, используемое для инициализации настройки сервера. Это хранилище называют также <factory-default>.

2. RPC factory-reset

Этот документ добавляет RPC factory-reset. При получении такого вызова выполняются указанные ниже действия.

  • Все поддерживаемые традиционные хранилища конфигурации с доступом для чтения и записи (т. е., <running>, <startup>, <candidate>) сбрасываются в состояние хранилища <factory-default>.

  • Доступные лишь для чтения хранилища получают своё содержимое из других хранилищ (например, <intended> берет содержимое <running>).

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

  • Содержимое хранилища <operational> должно отражать рабочее состояние устройства после применения заводских настроек.

В дополнение к этому вызов RPC factory-reset должен возвращать энергонезависимое хранилище в исходное (заводское) состояние. В зависимости от системы это может повлечь удаление созданных динамически файлов, таких как файлы с ключами (например, /etc/ssl/private), сертификатами (например, /etc/ssl), системными журналами (например, /var/log) и временные файлы (например, /tmp/*). Все криптографические ключи, относящиеся к заводским настройкам, такие как исходный сертификат идентификатор устройства (Initial Device Identifier или IDevID [BRSKI]) будут сохранены. Если этот процесс включает чувствительные к безопасности данные, такие как криптографические ключи или пароли, рекомендуется удалять их как можно тщательней (например, перезаписывая физический носитель нулями и/или случайными битами для перепрофилируемых или выводимых из эксплуатации носителей) для снижения риска утечки конфиденциальных сведений. Вызов RPC factory-reset можно также применять для запуска некоторых других задач сброса, таких как перезапуск устройства или некоторых программных процессов.

Отметим, что операторам следует учитывать возможность недоступности устройства через сеть в результате сброса всех доступных для чтения и записи хранилищ к заданным на заводе настройкам. Важно понимать, как будет вести себя устройство данного производителя после выполнения RPC. Оператору следует перезагрузить устройство и настроить его должным образом или запустить процесс начальной настройки (bootstrap).

3. Хранилище данных factory-default

Следуя руководствам по определению хранилищ данных из Приложения A к [RFC8342], этот документ вводит необязательное хранилище factory-default, представляющее исходную конфигурацию, которая позволяет инициализировать сервер. Устройство может реализовать RPC factory-reset без реализации хранилища factory-default, что будет лишь препятствовать возможности программными средствами определить заводскую конфигурацию.

Имя

factory-default.

Модули YANG

Схема хранилища данных factory-default должна (1) совпадать со схемой традиционных хранилищ конфигурации или (2) быть частью такой схемы.

Узлы YANG

Все узлы данных config true.

Операции управления

Содержимое хранилища устанавливается сервером в зависимости от реализации и не может быть изменено через протокол управления сетью (Network Configuration Protocol или NETCONF), RESTCONF, интерфейс CLI и т. п. без использования специализированных операций. Хранилище можно читать с использованием стандартных операций протоколов NETCONF и RESTCONF. Операция factory-reset копирует содержимое заданного на заводе хранилища в хранилище <running>, а также (при наличии) в <startup> и <candidate>. Содержимое обновлённых хранилищ автоматически распространяется в доступные лишь для чтения хранилища, такие как <intended> и <operational>.

Источник

Этот документ не задаёт новый идентификатор источника, поскольку он не связан с хранилищем <operational>.

Протоколы

RESTCONF, NETCONF и другие протоколы управления.

Модуль YANG сопределением

ietf-factory-default.

Содержимое <factory-default> определяет производитель устройства и оно должно сохраняться при перезапуске. Если поддерживается хранилище factory-default, оно должно включаться в список хранилищ библиотеки YANG [RFC8525].

4. Модуль YANG

This module uses the «datastore» identity [RFC8342] and the «default-deny-all» extension statement from [RFC8341].

   <CODE BEGINS> file "ietf-factory-default@2020-08-31.yang"
      module ietf-factory-default {
        yang-version 1.1;
        namespace "urn:ietf:params:xml:ns:yang:ietf-factory-default";
        prefix fd;

        import ietf-datastores {
          prefix ds;
          reference
            "RFC 8342: Network Management Datastore Architecture
             (NMDA)";
        }
        import ietf-netconf-acm {
          prefix nacm;
          reference
            "RFC 8341: Network Configuration Access Control Model";
        }

        organization
          "IETF Network Modeling (netmod) Working Group";
        contact
          "WG Web:   <https://datatracker.ietf.org/wg/netmod/>
           WG List:  <mailto:netmod@ietf.org>

           Editor:   Qin Wu
                     <mailto:bill.wu@huawei.com>

           Editor:   Balazs Lengyel
                     <mailto:balazs.lengyel@ericsson.com>

           Editor:   Ye Niu
                     <mailto:niuye@huawei.com>";
        description
          "Этот модуль обеспечивает функцию сброса устройства к заданным
           на заводе настройкам и (при поддержке) раскрытия содержимого 
           принятой по умолчанию заводской конфигурации независимо от
           сброса сервера.

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

           Распространение и использование в исходной или двоичной форме с
           изменениями или без таковых разрешено в соответствии с лицензией
           Simplified BSD, изложенной в разделе 4  IETF Trust's Legal
           Provisions применительно к документам IETF
           (http://trustee.ietf.org/license-info). 
 
           Эта версия данного модуля YANG является частью RFC 8808, где
           правовые вопросы рассмотрены более полно.";

        revision 2020-08-31 {
          description
            "исходный выпуск.";
          reference
            "RFC 8808: A YANG Data Model for Factory Default Settings";
        }

        feature factory-default-datastore {
          description
            "Указывает доступность хранилища заводских настроек.";
        }

        rpc factory-reset {
          nacm:default-deny-all;
          description
            "Сервер сбрасывает все хранилища и энергонезависимую память
             к заданным на заводе настройкам, удаляя все динамически
             созданные файлы, в том числе файлы с ключами, сертификатами
             и системными журналами (log), а также временные файлы.

             В зависимости от заданной на заводе конфигурации устройство
             после сброса может стать недоступным из сети.";
        }

        identity factory-default {
          if-feature "factory-default-datastore";
          base ds:datastore;
          description
            "Доступная лишь для чтения заводская конфигурация 
             устройства, используемая для замены содержимого доступных 
             для чтения и записи традиционных хранилищ данных 
             конфигурации с помощью RPC factory-reset.";
        }
      }
   <CODE ENDS>

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

Агентство IANA зарегистрировало URI в субреестре ns реестра IETF XML Registry [RFC3688].

   URI:  urn:ietf:params:xml:ns:yang:ietf-factory-default
   Registrant Contact:  The IESG.
   XML:  N/A; the requested URI is an XML namespace.

Агентство IANA зарегистрировало модуль YANG в субреестре YANG Module Names [RFC6020] реестра YANG Parameters.

   Name:  ietf-factory-default
   Namespace:  urn:ietf:params:xml:ns:yang:ietf-factory-default
   Prefix:  fd
   Reference:  RFC 8808

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

Заданные в этом документе модули YANG определяют схемы для данных, которые разработаны для доступа через протоколы управления сетью, такие как NETCONF [RFC6241] и RESTCONF [RFC8040]. Нижним уровнем NETCONF является защищённый транспорт с обязательной реализацией Secure Shell (SSH) [RFC6242]. Нижним уровнем RESTCONF служит HTTPS с обязательной реализацией защищённого транспорта TLS [RFC8446].

Модель управления доступом NETCONF [RFC8341] обеспечивает средства, позволяющие предоставить доступ лишь конкретным пользователям NETCONF и RESTCONF к предопределённому подмножеству доступных в NETCONF или RESTCONF протокольных операций и содержимого.

Доступ к операции RPC factory-reset и заводским значениям всех узлов данных конфигурации в хранилище factory-default считается чувствительным и поэтому его следует ограничивать с использованием оператора контроля доступа default-deny-all, определённого в [RFC8341].

RPC factory-reset может препятствовать управлению настройками устройства при сбросе сервера к заводским установкам. Например, конфигурация сессий и клиентов, включённая в принятые по умолчанию настройки или обрабатываемая как динамические файлы в энергонезависимой памяти, будет перезаписана RPC factory-reset.

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

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

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

7.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>.

[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>.

[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>.

[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>.

[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>.

[RFC8446] Rescorla, E., «The Transport Layer Security (TLS) Protocol Version 1.3», RFC 8446, DOI 10.17487/RFC8446, August 2018, <https://www.rfc-editor.org/info/rfc8446>.

[RFC8525] Bierman, A., Bjorklund, M., Schoenwaelder, J., Watsen, K., and R. Wilton, «YANG Library», RFC 8525, DOI 10.17487/RFC8525, March 2019, <https://www.rfc-editor.org/info/rfc8525>.

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

[BRSKI] Pritikin, M., Richardson, M. C., Eckert, T., Behringer, M. H., and K. Watsen, «Bootstrapping Remote Secure Key Infrastructures (BRSKI)», Work in Progress3, Internet-Draft, draft-ietf-anima-bootstrapping-keyinfra-43, 7 August 2020, <https://tools.ietf.org/html/draft-ietf-anima-bootstrapping-keyinfra-43>.

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

Спасибо Juergen Schoenwaelder, Ladislav Lhotka, Alex Campbell, Joe Clarke, Robert Wilton, Kent Watsen, Joel Jaeggli, Lou Berger, Andy Bierman, Susan Hares, Benjamin Kaduk, Stephen Kent, Stewart Bryant, Éric Vyncke, Murray Kucherawy, Roman Danyliw, Tony Przygienda, John Heasley за рецензии и существенный вклад в этот документ.

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

Rohit R Ranade
Huawei
Email: rohitrranade@huawei.com

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

Qin Wu
Huawei
Yuhua District
101 Software Avenue
Nanjing
Jiangsu, 210012
China
Email: bill.wu@huawei.com
 
Balazs Lengyel
Ericsson Hungary
Budapest
Magyar Tudosok korutja 11
1117
Hungary
Phone: +36-70-330-7909
Email: balazs.lengyel@ericsson.com
 
Ye Niu
Huawei
Email: niuye@huawei.com

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

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

nmalykh@protokols.ru

1Internet Engineering Task Force — комиссия по решению инженерных задач Internet.

2Internet Engineering Steering Group — комиссия по инженерным разработкам Internet.

3Опубликовано в RFC 8995. Прим. перев.

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

RFC 8802 The Quality for Service (Q4S) Protocol

Опубликована спецификация протокола Q4S

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

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

Документ доступен по ссылке.

Рубрика: RFC, Новости | Комментарии к записи RFC 8802 The Quality for Service (Q4S) Protocol отключены

Ограниченные домены и протоколы Internet

RFC 8799

Limited Domains and Internet Protocols

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

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

Текст документа доступен по ссылке, перевод доступен здесь.

Рубрика: RFC, Новости | Комментарии к записи Ограниченные домены и протоколы Internet отключены

Конкуренция с открытым кодом

Весьма любопытная статья, рекомендую

Конкуренция или сотрудничество: какую модель технологического развития выбрать России? Мы продолжаем дискуссию, начатую в «Стимуле» статьей Ивана Покровского
Рубрика: Новости | Комментарии к записи Конкуренция с открытым кодом отключены

RFC 8799 Limited Domains and Internet Protocols

Independent Submission                                      B. Carpenter
Request for Comments: 8799                             Univ. of Auckland
Category: Informational                                           B. Liu
ISSN: 2070-1721                                      Huawei Technologies
                                                               July 2020

Limited Domains and Internet Protocols

Ограниченные домены и протоколы Internet

PDF

Аннотация

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

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

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

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

Документ не связан с другими RFC и выбран для публикации редактором (RFC Editor) по своему усмотрению без каких-либо заявлений о ценности документа для внедрения или развертывания. Документы, одобренные для публикации RFC Editor, не претендуют на статус стандартов Internet (см. раздел 2 в RFC 7841).

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

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

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

К документу применимы права и ограничения, указанные в BCP 78 и IETF Trust Legal Provisions и относящиеся к документам IETF (http://trustee.ietf.org/license-info), на момент публикации данного документа. Прочтите упомянутые документы внимательно.

1. Введение

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

Некоторые люди опасаются раздела Internet по политическим или языковым границам с помощью механизмов блокировки свободного перемещения информации. Эта не является темой данного документа, которые не рассматривает механизмы фильтрации (см. [RFC7754]) и не применяется к протоколам, которые предназначены для применения во всей сети Internet. Здесь обсуждаются лишь домены с определенными техническими требованиями.

Термин «домен» в этом документе не относится к доменным именам DNS, хотя в некоторых случаях ограниченный домен может случайно совпадать с доменом DNS. В частности при конфигурации DNS с расщепленным горизонтом (split horizon) [RFC6950] раздел может проходить по краю ограниченного домена. Недавнее предложение определить периметры внутри DNS [DNS-PERIMETER] также может рассматриваться как механизм ограниченного домена.

Другим термином, который используется в ином контексте, является «контролируемая среда» (controlled environment). Например в [RFC8085] этот термин служит для обозначения границ области действия, в которой может применяться определенная туннельная инкапсуляция. Конкретным примером является инкапсуляция GRE-in-UDP [RFC8086], в которой четко указано: «контролируемая среда предъявляет менее строгие требования, нежели Internet.» Например, трафик без контроля перегрузок может быть приемлемым в контролируемой среде. Эта же фраза может применяться для обозначения области действия протоколов QoS1 [RFC6398]. Это не обязательно тот случай, где протоколы будут отказывать (fail) за пределами контролируемой среды, но они могут работать неоптимально. В этом документе предполагается, что на практике термины «ограниченный домен» и «контролируемая среда» означают одно и то же. Термин «управляемая сеть» (managed network) используется аналогичным образом, например, в [RFC6947]. В контексте защищенной групповой адресации определен термин «домен интерпретации для группы» (group domain of interpretation) [RFC6407].

Еще больше определений типов доменов имеется в документах о маршрутизации, таких как [RFC4397], [RFC4427], [RFC4655]. Понятие ограниченного домена используется весьма широко в разных аспектах технологий Internet.

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

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

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

2. Текущие отказы в Internet

Сегодня в Internet нет четкой концепции ограниченных доменов. В результате этого некоторые протоколы и функции не работают на определенных путях. Прежний анализ этой проблем концентрировался на потере «прозрачности» Internet [RFC2775], [RFC4924] или ответственности промежуточных узлов за такую потерю [RFC3234], [RFC7663], [RFC8517]. К сожалению проблемы возникают как в прикладных протоколах, так и в фундаментальных механизмах. Например, в Internet нет прозрачности для заголовков расширения IPv6 [RFC7872], а механизм Path MTU Discovery не обеспечивал надежности в течение многих лет [RFC2923], [RFC4821]. Фрагментация IP также ненадежна [FRAG-FRAGILE] и отмечены проблемы согласования TCP MSS [IPV6-USE-MINMTU].

С точки зрения безопасности широкое применение межсетевых экранов на границах сетей, воспринимаемых людьми, но неизвестных протоколам, ведет к различным отказам на прикладных уровнях. Имее реальный опыт и рекомендации, гарантированно при эффективного boundaries that are perceived by humans but unknown to protocols results in arbitrary failure modes as far as the application layer is concerned. There are operational recommendations and practices that effectively guarantee arbitrary failures in realistic scenarios [IPV6-EXT-HEADERS].

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

Исследования ненадежности фрагментации IP [FRAG-FRAGILE] и фильтрации заголовков расширения IPv6 [RFC7872] убедительно показывают потерю прозрачности по меньшей мере для некоторых протокольных элементов и промежуточные устройства играют здесь свою роль. В двух следующих параграфах рассмотрены некоторые среды приложений, требующие свойств протоколов, которые невозможно или не следует поддерживать в масштабе Internet.

3. Примеры требований ограниченного домена

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

  1. Домашняя сеть. Это обычно неуправляемая сеть созданная не специалистом. Сеть должна работать с «устройствами из коробки» от производителя и обеспечивать по умолчанию адекватный уровень защиты. Может потребоваться удаленный доступ. Требования и применимые принципы описаны в [RFC7368].

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

  3. Сеть транспортного средства. Такие сети создаются производителями транспортных средств и могут включать устройства, добавленные владельцем или оператором транспортного средства. К элементам сети предъявляются высокие требования по надежности и производительности, оказывающие влияние на безопасность людей. Для некоторых функций может требоваться удаленный доступ, тогда как к другим он должен быть полностью запрещен. Требуется связь с другими транспортными средствами, дорожной инфраструктурой и внешними источниками данных. Примеры рассмотрены в [IPWAVE-NETWORKING].

  4. Сети SCADA2 и другие сети, работающие в реальном масштабе времени. Эти сети предъявляют конкретные требования, включая жесткие показатели работы в режиме реального времени. Множество примеров таких сетей рассмотрено в [RFC8578]. Одним из примеров является сеть строительных служб, разработанная специально для строительства конкретного здания, но с использованием стандартных компонентов. В любой момент может потребоваться добавление в сеть новых устройств. Отдельные части могут предъявлять высоркие требования к надежности, связанные с безопасностью людей. Может требоваться удаленный доступ к некоторым функциям при полном запрете доступа к другим. Крайним случаяем является сеть, используемая для приложений виртуальной или дополненной реальности с высокими требованиями к задержкам.

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

  6. Сети IoT3. Этот термин очень гибок и охватывает многие инновационные типы сетей, включая специализированные (ad hoc) сети, формируемые спонтанно, и некоторые приложения 5G, представляется разумным считать, что пограничные сети IoT будут предъявлять специальные требования и использовать протоколы, которые полезны лишь в конкретном домене и из соображений безопасности не могут применяться для работы через Internet.

  7. Сети устройств с ограниченными возможностями. Важным подклассом сетей IoT являются сети устройств с ограниченными возможностями [RFC7228], в которых узлы ограничены по энергопотреблению и пропускной способности, что требует использования очень экономных протоколов.

  8. Устойчивые к задержкам сети могут состоять из сравнительно изолированных доменов, быть ограниченными по питанию (например, размещаться в глубоком космосе) и подключаться лишь периодически с очень большой задержкой в соединениях [RFC4838].Понятно, что требования к протоколам для таких сетей специфичны.

  9. Традиционные сети предприятий и кампусов могут иметь значительную протяженность и включать множество сайтов со своим подключением к Internet. Интересно, что в рамках IETF такой вариант давно существующих сетей не анализировался в общем виде, за исключениям случаев, связанных с развертыванием IPv6 (например, [RFC7381]).

  10. Неприемлемые стандарты. В корпоративных сетях могут возникать ситуации, когда решение, подходящее для Internet может приводить к локальным отказам или быть слишком сложным. Примером могут быть сложности, вызванные такими механизмами как ICE4 [RFC8445], не оправданными внутри сети. Кроме того, ICE в некоторых случаях невозможно использовать по причине неизвестности адресов-кандидатов до организации соединения, в результате чего может требоваться иное локальное решение [RFC6947].

  11. Управляемые распределенные сети сервис-провайдеров и предприятий, такие как соединения «точка-точка» на уровне L2 (Ethernet и т. п.) с использованием псевдопроводов, многоточечные L2 Ethernet VPNs, использующие услуги VPLS5, или Ethernet VPN (EVPN) и L3 IP VPN. Обычно они характеризуются соглашениями об уровне обслуживания я части доступности, потери пакетов и, возможно, групповых служб. Это отличается от предыдущего случая тем, что используются такие сети в основном на инфраструктурах MPLS, требования к которым четко заданы IETF.

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

  13. Сети CDN6, состоящие из распределенных ЦОД и путей между ними, простирающихся на тысячи километров. Множество подключений к Internet.

  14. Крупные сети Web. Небольшой класс общеизвестных сетей, объединяющих в себе аспекты распределенных корпоративных сетей, ЦОД и CDN. Они имеют свои транснациональные сети в обход традиционных опереторов. Кодобно CDN, они имеют множество соединений с Internet, обычно предлагая свои услуги в каждой стране.

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

  1. Многие из перечисленных типов сетей могут включать соединения через Internet на основе методов VPN7. Поэтому можно утверждать, что ограниченные домены могут перекрываться между собой с использованием методов виртуализации. Как отмечено выше, для использования в конкретном домене могут быть приспособлены те или иные методы туннелирования и инкапсуляции.

  2. В сетях на основе намерений (intent-based) домены настраиваются и управляются в соответствии с абстрактной политикой, называемой намерением (Intent), для обеспечения подобающей работы сети [IBN-CONCEPTS]. Какие бы технологии не использовались для поддержки этого, они будут применяться в границах домена, даже если поддерживаемые доменом службы доступны глобально.

  3. «Нарезка» сетей (network slicing) является формой виртуальной сети, состоящей из управляемого набора ресурсов, взятого из более крупной сети [ENHANCED-VPN]. Предполагается, что этот подход станет значимым в сетях 5G [USER-PLANE-PROTOCOL]. Какие бы технологии не применялись для «нарезки», потребуется четкое определение границ каждого «среза» в более крупном домене.

Хотя желание использовать общие решения и стандарты очевидно, это становится все трудней обеспечить с учетом широко меняющихся требований, перечисленных выше. Тем не менее, имеется тенденция при создании новых протоколов и расширений задаваться вопросом, как это будет работать через открытую сеть Internet. Здесь предлагается несколько иной подход — считать некоторые протоколы и расширения не предназначенными для работы через Internet. Требования и семантика таких протоколов имеют существенные ограничения (в отмеченном смысле).

Принято считать, что протоколы, предназначенные для ограниченного применения, имеют много шансов оказаться используемыми (возможно, некорректно) в других ситуациях, включая открытую сеть Internet. Это верно и означает, что ограниченное применение протокола не означает снижения требований к его устройству и безопасности. Фактически, протоколы ограниченного применения являются более сложными и предъявляют более высокие требования к безопасности, как будет показано ниже.

Тем не менее, разнообразие ограниченных доменов с особыми характеристиками вероятно приведет к появлению конкретных стандартов (включая ad hoc) для различных типов доменов. Будут предприняты попытки охватить каждый сектор рынка, но рынок потребует стандартизации решений в каждом секторе. Кроме того, будут приняты решения, которые фактически будут работать лишь в ограниченных доменах. История RSVP [RFC2205] показывает, что стандарт, созданный для работы через открытую сеть Internet, на деле этого не может. В общем случае больше нельзя считать, что протоколы, созданные по классическим правилам Internet, смогут реально работать во всей сети. Однако «открытая сеть Internet» должна оставаться универсальным средством соединения. Устранение этого конфликта является сложной задачей.

4. Примеры ограниченных доменов

В этом разделе перечислены примеры ограниченных доменов, которые были предложены или определены. Здесь намеренно не включены разные технологические решения L2, которые по определению применяются в разных доменах. Тем не менее, следует отметить, что с учетом недавних разработок, таких как TRILL8 [RFC6325] и [SPB9], домены L2 могут быть очень большими.

  1. Дифференцированные услуги. Механизм [RFC2474] позволяет сети назначать 6-битовые значения кодов обслуживания DSCP10 с локальной значимостью каждому пакету IP. Имеются рекомендации по выделению кодов для управления поведением очередей на этапе пересылки, однако в целом эти коды предназначены для классификации, кондиционирования и (пере)маркировки пакетов на границах домена (если нет междоменного соглашения о маркировке пакетов).

  2. Интегрированные услуги. Хотя этот механизм и не является неотъемлемой частью RSVP [RFC2205], многие годы эксплуатации показали, что интегрированные услуги можно эффективно реализовать лишь в ограниченном домене с подобающей настройкой оборудования и ресурсов.

  3. Виртуализация сетевых функций. Как отмечено в [RFC8568], эта базовая концепция является темой продожающихся исследований систем, где виртуализованные сетевые функции организованы как часть распределенной системы. Такая организация функций с неизбежностью ведет к использованию того или иного домена с ограничениями, несмотря на то, что междоменная организация (оркестровки) тоже является предметом исследований.

  4. Цепочки сервисных функций (SFC11). Этот метод [RFC7665] предполагает, что сетевые службы представляют собой цепочки отдельных сервисных функций внутри конкретного домена SFC (например, 5G). Как отмечено в RFC: «Возможно потребуется применять определенные функции на границе домена SFC, например, для предотвращения утечки информации SFC». Для инкапсуляции пакетов, проходящих через цепочку функций, применяются заголовки NSH12 [RFC8300]: «Предполагаемая область действия NSH — один домен провайдера».

  5. Квитанции FAST13 сопровождают пакет, позволяя тому проходить через сеть или запрашвать конкретную сетевыую услугу [FAST]. «Билеты» имеют значение лишь в конкретном домене.

  6. Наложенные виртуальные сети ЦОД. Общим требованием ЦОД, где размещается оборудование множества арендаторов (клиентов), является предоставление каждому клиенту защищенной частной сети, но при этом сети всех клиентов должны работать на основе общей физической инфраструктуры. В [RFC8151] описаны различные варианты решений, а также рассмотрены разрабатываемые спецификации. Включены также ситуации, где сеть арендатора физически разделена между несколькими ЦОД, но должна представляться пользователям как единый защищенный домен.

  7. Сегментная маршрутизация. Этот метод «ведет пакет через упорядоченный список инструкций, называемых сегментами» [RFC8402]. Семантика инструкция является локаотной для домена сегментной маршрутизации или даже для одного узла. Технически эти сегменты или инструкции представляются как метки MPLS или адреса IPv6, обеспечивающие их сементическую интерпретацию в домене.

  8. Автономные сети. Как указано в [REF-MODEL], автономная сеть является также доменом безопасности, в котором агенты автономных служб используют автономную плоскость (уровень) управления [ACP]. These agents manage technical objectives, which may be locally defined, subject to domain-wide policy. Thus, the domain boundary is important for both security and protocol purposes.

  9. Домовые сети. Как показано в [RFC7368], домашние сети имеют свои требования к протоколам, отличающиеся от требований корпоративных сетей и Internet в целом. Это включает протокол HNCP14 [RFC7788], а также решение [HOMENET-NAMING] для именования и обнаружения.

  10. Творческое использование свойств IPv6. Протокол IPv6 обеспечивает большую по сравнению с IPv4 гибкость.

    • Метки потоков, например, [RFC6294].

    • Заголовки расширений, например, для сегментной маршрутизации [RFC8754] или маркировки OAM15 [IPV6-ALT-MARK].

    • Значимые биты адресов, например, [EMBEDDED-SEMANTICS]. Сегментная маршрутизация использует адреса IPv6 в качестве идентификаторов сегментов с локальной значимостью [RFC8402].

    • При использовании сегментной маршрутизации для программирования сети [SRV6-NETWORK] заголовки расширений IPv6 могут применяться взамен более сложной локальной функциональности.

    Заголовки расширений особенно интересны, поскольку их наличие является основной «точкой продажи» IPv6, однако новые заголовки практически невозможно размернуть в масштабе Internet [RFC7045] [RFC7872]. Следует отметить, что фильтрация заголовков считается важной проблемой безопасности [IPV6-EXT-HEADERS]. Прозводители и операторы стремятся гибко определять заголовки расширения для использования в ограниченных или специализированных доменах, например, [IPV6-SRH], [BIGIP], [APP-AWARE]. Предусмотрены также локально значимые поэтапные (hop-by-hop) опции, понятные маршрутизаторам внутри домена, но не внешним устройствам (например, [IN-SITU-OAM]).

  11. Детерминированные сети (DetNet). Архитектура [RFC8655] и инкапсуляция [DETNET-DATA-PLANE] нацелены на поддержку потоков с экстемально низкими потерями данных и ограниченной задержкой, но лишь в части сети, понимающей DetNet. Как и для дифференцированных услуг концепция является фундаментальной.

  12. Домены обеспечения (PvD). Архитектура [RFC7556] позволяет хостам, подключенным к нескольким сетям, явно узнавать детали услуг, предоставляемых каждой сетью.

  13. Область действия адресов. Отметим, что некоторые адреса, в частности IPv6, имеют явно ограниченную область действия. Например локальные для канала адреса (link-local) действуют лишь на одном физическом соединении [RFC4291], а уникальные локальные адреса [RFC4193] ограничены слабо определенной областью локального сайта. Были определены также локальные для сайта адреса (site-local), но их сочли устаревшими по причине нечеткости концепции сайта [RFC3879]. Групповые адреса также явно ограничены в области действия [RFC4291].

  14. В качестве примера прикладного уровня можно указать потоковые службы, такие как инфраструктура IPTV, которые основаны на стандартных протоколах, но не предоставляют глобального доступа.

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

5. Область действия протоколов в ограниченных доменах

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

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

  1. Если домен разделен на две части, связанные через Internet непосредственно на уровне IP (т. е. без туннельной инкапсуляции), протокол ограниченного домена независимо от своей специальной природы, если он использует стандартные форматы IP и не блокируется межсетевыми экранами. Простым примером является использование специального номера порта для протокола не-IETF.

    Такой протокол можно считать междоменным, поскольку сеть Internet прозрачна для него, даже если протокол имеет смысл лишь в ограниченном домене. Это не вносит ничего нового в архитектуру Internet.

  2. Есди протокол ограниченного домена не соответствует стандартным форматам IP (например, включает нестандартный заголовок расширения IPv6), он не сможет работать между парой доменов, соединенных напрямую через Internet на уровне IP.

    Такие протоколы можно называть внутридоменными и сеть Internet «непрозрачна» для них.

  3. Если для протокола ограниченного домена явно указана непригодность за пределами домена, ни один из вариантов A и B не применим. Единственным решением будет создание общего виртуального домена. Например, можно использовать туннельную инкапсуляцию для создания общего виртуального домена. На границе домена все пакеты такого протокола должны отбрасываться.

  4. Если протокол ограниченного домена имеет специфические для доменов варианты, реализации в разных доменах могут оказаться несовместимыми при соединении доменов по варианту C. Протокол при таком соединении может приводить к непредсказуемым отказам. Простым примером является любой протокол, использующий выделенный для эеспериментов номер порта. Связанные с этим вопросы рассматриваются в [RFC5704], включая достаточно сложный вариант использования Transport MPLS.

В качестве распространенного примера рассмотрим дифференцированные услуги [RFC2474]. Пакет с любым значением в 6 битах поля DSCP17 имеет корректный формат для варианта A. Однако семантика кодов DSCP имеет локальную значимость, поэтому применим также вариант D. Фактически дифференцированные услуги могут поддерживаться через границы доменов лишь при наличии соответствующего соглашения между операторами. В иных случаях для полноценного взаимодействия нужны специальные функции на шлюзе. Более подробно это рассмотрено в [RFC2474] и [RFC8100].

В качестве провокационного примера рассмотрим предложенное в [IPV6-SRH] смягчение ограничений [RFC8200], позволяющее вставлять заголовки расширения в пакеты IPv6 «на лету». Если это делать так, чтобы измененные пакеты никогда не покидали ограниченный домен, применим вариант C. Если семантика вставляемых заголовков определена локально, применим также вариант D. В обоих случаях работа Internet за пределами ограниченного домена не нарушается. Однако внутри домена узлы должны понимать вариант протокола. Если вариант не стандартизован в виде формальной версии в учетом всех обстоятельств, предусмотренных [RFC6709], все узлы должны быть нестандартными для понимания варианта протокола. Для случая вставки заголовков расширения IPv6 это означает несоответствие [RFC8200] внутри домена даже при полном соответствии стандарту самих вставляемых заголовков. Помимо проблемы формального соответствия такие отклонения могут значительно усложнять отладку. Возможное практическое влияние такой вставки заголовков рассмотрено в [IN-FLIGHT-IPV6].

Отмеченное в разделе 4 (п. 5) предложение FAST также дает интересный пример. Семантика квитанций FAST [FAST] имеет ограниченную область действия. Однако они разработаны так, что в принципе могут передаваться через Internet в форме стандартизованных опций IPv6 hop-by-hop или даже в заголовках расширения IPv4 [IPV4-EXT-HEADERS]. Вопрос надежности использования таких вариантов в открытой сети Internet остается неясным [IPV6-EXT-HEADERS].

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

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

6. Функциональные требования ограниченных доменов

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

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

Во-первых, создание топологического плана (карты) данного домена (физического или виртуального) позволяет четко определить границу домена. Однако сама по себе граница не имеет технического значения. На деле важна принадлежность узлов к домену и факт размещения узлов на границе между доменом и остальной частью Internet. Таким образом, важна идентификация не самой границы, а узлов, имеющих интерфейсы внутрь домена и наружу. Внутри домена передающему узлу нужно понимать, расположен адресат внутри или вне домена, а принимающим — получен пакет от внешнего или внутреннего узла. Граничным узлам следует различать свои внутренние и внешние интерфейсы (как физические, так и виртуальные).

Чтобы подчеркнуть важность идентификации границы домена, отметим проблему детерминированных сетей [RFC8557], где «все еще недостаточно четко определены границы домена, в котором может быть оганизован детерминированный путь». Это замечание можно обобщить.

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

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

  2. Вложенность. Домены могут быть вложенными (см. приведенный выше пример «нарезки сетей»).

  3. Наложение. Узлы и каналы могут входить в несколько доменов (см. упомянутый выше случай PvD).

  4. Выбор для узла. Узел должен иметь возможность определить домены, к которым он может присоединиться и применяемые для этого интерфейсы.

  5. Безопасная регистрация. Узел должен иметь возможность зарегистрироваться в данном домене, используя безопасную идентификацию, и получить ссответствующие свидетельства (предоставление полномочий) для выполнения операций в домене. На узлах с несколькими физическими или виртуальными интерфейсами может потребоваться отдельная регистрация для каждого интерфейса.

  6. Отзыв. Узел должен иметь возможность отозвать регистрацию в данном домене.

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

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

  9. Проверка партнеров. Узел должен иметь возможность проверки принадлежности своего партнера к домену.

  10. Проверка роли. Узлу слудует обеспечивать возможность проверки роли партнера. В частности, следует обеспечивать возможность нахождения граничных узлов (с интерфейсом в Internet).

  11. Данные домена. В домене с требованиями по управления узлам должна обеспечиваться возможность получить правила и/или конфигурационные данные домена. Это включает, например, пакеты, которые не должны покидать домен.

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

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

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

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

Зачастую периметр домена с ограничениями является также границей защиты. В частности, периметр является границей доверия и полномочий доступа к определенным возможностям. Например, сегментная маршрутизация [RFC8402] явно использует для концепцию «домена доверия». Внутри периметра протоколы или свойства ограниченного домена могут быть полезны, но за пределами домена они могут становиться ненужными или вредными.

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

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

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

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

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

[ACP] Eckert, T., Behringer, M., and S. Bjarnason, «An Autonomic Control Plane (ACP)», Work in Progress, Internet-Draft, draft-ietf-anima-autonomic-control-plane-27, 2 July 2020, <https://tools.ietf.org/html/draft-ietf-anima-autonomic-control-plane-27>.

[APP-AWARE] Li, Z., Peng, S., Li, C., Xie, C., Voyer, D., Li, X., Liu, P., Liu, C., and K. Ebisawa, «Application-aware IPv6 Networking (APN6) Encapsulation», Work in Progress, Internet-Draft, draft-li-6man-app-aware-ipv6-network-02, 2 July 2020, <https://tools.ietf.org/html/draft-li-6man-app-aware-ipv6-network-02>.

[BIGIP] Li, R., «HUAWEI — Big IP Initiative», 2018, <https://www.iaria.org/announcements/HuaweiBigIP.pdf>.

[DETNET-DATA-PLANE] Varga, B., Farkas, J., Berger, L., Malis, A., and S. Bryant, «DetNet Data Plane Framework», Work in Progress, Internet-Draft, draft-ietf-detnet-data-plane-framework-06, 6 May 2020, <https://tools.ietf.org/html/draft-ietf-detnet-data-plane-framework-06>.

[DNS-PERIMETER] Crocker, D. and T. Adams, «DNS Perimeter Overlay», Work in Progress, Internet-Draft, draft-dcrocker-dns-perimeter-01, 11 June 2019, <https://tools.ietf.org/html/draft-dcrocker-dns-perimeter-01>.

[EMBEDDED-SEMANTICS] Jiang, S., Qiong, Q., Farrer, I., Bo, Y., and T. Yang, «Analysis of Semantic Embedded IPv6 Address Schemas», Work in Progress, Internet-Draft, draft-jiang-semantic-prefix-06, 15 July 2013, <https://tools.ietf.org/html/draft-jiang-semantic-prefix-06>.

[ENHANCED-VPN] Dong, J., Bryant, S., Li, Z., Miyasaka, T., and Y. Lee, «A Framework for Enhanced Virtual Private Networks (VPN+) Service», Work in Progress, Internet-Draft, draft-ietf-teas-enhanced-vpn-06, 13 July 2020, <https://tools.ietf.org/html/draft-ietf-teas-enhanced-vpn-06>.

[FAST] Herbert, T., «Firewall and Service Tickets», Work in Progress, Internet-Draft, draft-herbert-fast-04, 10 April 2019, <https://tools.ietf.org/html/draft-herbert-fast-04>.

[FRAG-FRAGILE] Bonica, R., Baker, F., Huston, G., Hinden, R., Troan, O., and F. Gont, «IP Fragmentation Considered Fragile», Work in Progress, Internet-Draft, draft-ietf-intarea-frag-fragile-17, 30 September 2019, <https://tools.ietf.org/html/draft-ietf-intarea-frag-fragile-17>.

[HOMENET-NAMING] Lemon, T., Migault, D., and S. Cheshire, «Homenet Naming and Service Discovery Architecture», Work in Progress, Internet-Draft, draft-ietf-homenet-simple-naming-03, 23 October 2018, <https://tools.ietf.org/html/draft-ietf-homenet-simple-naming-03>.

[IBN-CONCEPTS] Clemm, A., Ciavaglia, L., Granville, L., and J. Tantsura, «Intent-Based Networking — Concepts and Definitions», Work in Progress, Internet-Draft, draft-irtf-nmrg-ibn-concepts-definitions-01, 9 March 2020, <https://tools.ietf.org/html/draft-irtf-nmrg-ibn-concepts-definitions-01>.

[IN-FLIGHT-IPV6] Smith, M., Kottapalli, N., Bonica, R., Gont, F., and T. Herbert, «In-Flight IPv6 Extension Header Insertion Considered Harmful», Work in Progress, Internet-Draft, draft-smith-6man-in-flight-eh-insertion-harmful-02, 30 May 2020, <https://tools.ietf.org/html/draft-smith-6man-in-flight-eh-insertion-harmful-02>.

[IN-SITU-OAM] Bhandari, S., Brockners, F., Pignataro, C., Gredler, H., Leddy, J., Youell, S., Mizrahi, T., Kfir, A., Gafni, B., Lapukhov, P., Spiegel, M., Krishnan, S., and R. Asati, «In-situ OAM IPv6 Options», Work in Progress, Internet-Draft, draft-ietf-ippm-ioam-ipv6-options-02, 13 July 2020, <https://tools.ietf.org/html/draft-ietf-ippm-ioam-ipv6-options-02>.

[IPV4-EXT-HEADERS] Herbert, T., «IPv4 Extension Headers and Flow Label», Work in Progress, Internet-Draft, draft-herbert-ipv4-eh-01, 2 May 2019, <https://tools.ietf.org/html/draft-herbert-ipv4-eh-01>.

[IPV6-ALT-MARK] Fioccola, G., Zhou, T., Cociglio, M., Qin, F., and R. Pang, «IPv6 Application of the Alternate Marking Method», Work in Progress, Internet-Draft, draft-ietf-6man-ipv6-alt-mark-01, 22 June 2020, <https://tools.ietf.org/html/draft-ietf-6man-ipv6-alt-mark-01>.

[IPV6-EXT-HEADERS] Gont, F. and W. LIU, «Recommendations on the Filtering of IPv6 Packets Containing IPv6 Extension Headers», Work in Progress, Internet-Draft, draft-ietf-opsec-ipv6-eh-filtering-06, 2 July 2018, <https://tools.ietf.org/html/draft-ietf-opsec-ipv6-eh-filtering-06>.

[IPV6-SRH] Voyer, D., Filsfils, C., Dukes, D., Matsushima, S., Leddy, J., Li, Z., and J. Guichard, «Deployments With Insertion of IPv6 Segment Routing Headers», Work in Progress, Internet-Draft, draft-voyer-6man-extension-header-insertion-09, 19 May 2020, <https://tools.ietf.org/html/draft-voyer-6man-extension-header-insertion-09>.

[IPV6-USE-MINMTU] Andrews, M., «TCP Fails To Respect IPV6_USE_MIN_MTU», Work in Progress, Internet-Draft, draft-andrews-tcp-and-ipv6-use-minmtu-04, 18 October 2015, <https://tools.ietf.org/html/draft-andrews-tcp-and-ipv6-use-minmtu-04>.

[IPWAVE-NETWORKING] Jeong, J., «IPv6 Wireless Access in Vehicular Environments (IPWAVE): Problem Statement and Use Cases», Work in Progress, Internet-Draft, draft-ietf-ipwave-vehicular-networking-16, 7 July 2020, <https://tools.ietf.org/html/draft-ietf-ipwave-vehicular-networking-16>.

[REF-MODEL] Behringer, M., Carpenter, B., Eckert, T., Ciavaglia, L., and J. Nobre, «A Reference Model for Autonomic Networking», Work in Progress, Internet-Draft, draft-ietf-anima-reference-model-10, 22 November 2018, <https://tools.ietf.org/html/draft-ietf-anima-reference-model-10>.

[RFC2205] Braden, R., Ed., Zhang, L., Berson, S., Herzog, S., and S. Jamin, «Resource ReSerVation Protocol (RSVP) — Version 1 Functional Specification», RFC 2205, DOI 10.17487/RFC2205, September 1997, <https://www.rfc-editor.org/info/rfc2205>.

[RFC2474] Nichols, K., Blake, S., Baker, F., and D. Black, «Definition of the Differentiated Services Field (DS Field) in the IPv4 and IPv6 Headers», RFC 2474, DOI 10.17487/RFC2474, December 1998, <https://www.rfc-editor.org/info/rfc2474>.

[RFC2775] Carpenter, B., «Internet Transparency», RFC 2775, DOI 10.17487/RFC2775, February 2000, <https://www.rfc-editor.org/info/rfc2775>.

[RFC2923] Lahey, K., «TCP Problems with Path MTU Discovery», RFC 2923, DOI 10.17487/RFC2923, September 2000, <https://www.rfc-editor.org/info/rfc2923>.

[RFC3234] Carpenter, B. and S. Brim, «Middleboxes: Taxonomy and Issues», RFC 3234, DOI 10.17487/RFC3234, February 2002, <https://www.rfc-editor.org/info/rfc3234>.

[RFC3879] Huitema, C. and B. Carpenter, «Deprecating Site Local Addresses», RFC 3879, DOI 10.17487/RFC3879, September 2004, <https://www.rfc-editor.org/info/rfc3879>.

[RFC4193] Hinden, R. and B. Haberman, «Unique Local IPv6 Unicast Addresses», RFC 4193, DOI 10.17487/RFC4193, October 2005, <https://www.rfc-editor.org/info/rfc4193>.

[RFC4291] Hinden, R. and S. Deering, «IP Version 6 Addressing Architecture», RFC 4291, DOI 10.17487/RFC4291, February 2006, <https://www.rfc-editor.org/info/rfc4291>.

[RFC4397] Bryskin, I. and A. Farrel, «A Lexicography for the Interpretation of Generalized Multiprotocol Label Switching (GMPLS) Terminology within the Context of the ITU-T’s Automatically Switched Optical Network (ASON) Architecture», RFC 4397, DOI 10.17487/RFC4397, February 2006, <https://www.rfc-editor.org/info/rfc4397>.

[RFC4427] Mannie, E., Ed. and D. Papadimitriou, Ed., «Recovery (Protection and Restoration) Terminology for Generalized Multi-Protocol Label Switching (GMPLS)», RFC 4427, DOI 10.17487/RFC4427, March 2006, <https://www.rfc-editor.org/info/rfc4427>.

[RFC4655] Farrel, A., Vasseur, J.-P., and J. Ash, «A Path Computation Element (PCE)-Based Architecture», RFC 4655, DOI 10.17487/RFC4655, August 2006, <https://www.rfc-editor.org/info/rfc4655>.

[RFC4821] Mathis, M. and J. Heffner, «Packetization Layer Path MTU Discovery», RFC 4821, DOI 10.17487/RFC4821, March 2007, <https://www.rfc-editor.org/info/rfc4821>.

[RFC4838] Cerf, V., Burleigh, S., Hooke, A., Torgerson, L., Durst, R., Scott, K., Fall, K., and H. Weiss, «Delay-Tolerant Networking Architecture», RFC 4838, DOI 10.17487/RFC4838, April 2007, <https://www.rfc-editor.org/info/rfc4838>.

[RFC4924] Aboba, B., Ed. and E. Davies, «Reflections on Internet Transparency», RFC 4924, DOI 10.17487/RFC4924, July 2007, <https://www.rfc-editor.org/info/rfc4924>.

[RFC5704] Bryant, S., Ed., Morrow, M., Ed., and IAB, «Uncoordinated Protocol Development Considered Harmful», RFC 5704, DOI 10.17487/RFC5704, November 2009, <https://www.rfc-editor.org/info/rfc5704>.

[RFC6294] Hu, Q. and B. Carpenter, «Survey of Proposed Use Cases for the IPv6 Flow Label», RFC 6294, DOI 10.17487/RFC6294, June 2011, <https://www.rfc-editor.org/info/rfc6294>.

[RFC6325] Perlman, R., Eastlake 3rd, D., Dutt, D., Gai, S., and A. Ghanwani, «Routing Bridges (RBridges): Base Protocol Specification», RFC 6325, DOI 10.17487/RFC6325, July 2011, <https://www.rfc-editor.org/info/rfc6325>.

[RFC6398] Le Faucheur, F., Ed., «IP Router Alert Considerations and Usage», BCP 168, RFC 6398, DOI 10.17487/RFC6398, October 2011, <https://www.rfc-editor.org/info/rfc6398>.

[RFC6407] Weis, B., Rowles, S., and T. Hardjono, «The Group Domain of Interpretation», RFC 6407, DOI 10.17487/RFC6407, October 2011, <https://www.rfc-editor.org/info/rfc6407>.

[RFC6709] Carpenter, B., Aboba, B., Ed., and S. Cheshire, «Design Considerations for Protocol Extensions», RFC 6709, DOI 10.17487/RFC6709, September 2012, <https://www.rfc-editor.org/info/rfc6709>.

[RFC6947] Boucadair, M., Kaplan, H., Gilman, R., and S. Veikkolainen, «The Session Description Protocol (SDP) Alternate Connectivity (ALTC) Attribute», RFC 6947, DOI 10.17487/RFC6947, May 2013, <https://www.rfc-editor.org/info/rfc6947>.

[RFC6950] Peterson, J., Kolkman, O., Tschofenig, H., and B. Aboba, «Architectural Considerations on Application Features in the DNS», RFC 6950, DOI 10.17487/RFC6950, October 2013, <https://www.rfc-editor.org/info/rfc6950>.

[RFC7045] Carpenter, B. and S. Jiang, «Transmission and Processing of IPv6 Extension Headers», RFC 7045, DOI 10.17487/RFC7045, December 2013, <https://www.rfc-editor.org/info/rfc7045>.

[RFC7228] Bormann, C., Ersue, M., and A. Keranen, «Terminology for Constrained-Node Networks», RFC 7228, DOI 10.17487/RFC7228, May 2014, <https://www.rfc-editor.org/info/rfc7228>.

[RFC7368] Chown, T., Ed., Arkko, J., Brandt, A., Troan, O., and J. Weil, «IPv6 Home Networking Architecture Principles», RFC 7368, DOI 10.17487/RFC7368, October 2014, <https://www.rfc-editor.org/info/rfc7368>.

[RFC7381] Chittimaneni, K., Chown, T., Howard, L., Kuarsingh, V., Pouffary, Y., and E. Vyncke, «Enterprise IPv6 Deployment Guidelines», RFC 7381, DOI 10.17487/RFC7381, October 2014, <https://www.rfc-editor.org/info/rfc7381>.

[RFC7556] Anipko, D., Ed., «Multiple Provisioning Domain Architecture», RFC 7556, DOI 10.17487/RFC7556, June 2015, <https://www.rfc-editor.org/info/rfc7556>.

[RFC7663] Trammell, B., Ed. and M. Kuehlewind, Ed., «Report from the IAB Workshop on Stack Evolution in a Middlebox Internet (SEMI)», RFC 7663, DOI 10.17487/RFC7663, October 2015, <https://www.rfc-editor.org/info/rfc7663>.

[RFC7665] Halpern, J., Ed. and C. Pignataro, Ed., «Service Function Chaining (SFC) Architecture», RFC 7665, DOI 10.17487/RFC7665, October 2015, <https://www.rfc-editor.org/info/rfc7665>.

[RFC7754] Barnes, R., Cooper, A., Kolkman, O., Thaler, D., and E. Nordmark, «Technical Considerations for Internet Service Blocking and Filtering», RFC 7754, DOI 10.17487/RFC7754, March 2016, <https://www.rfc-editor.org/info/rfc7754>.

[RFC7788] Stenberg, M., Barth, S., and P. Pfister, «Home Networking Control Protocol», RFC 7788, DOI 10.17487/RFC7788, April 2016, <https://www.rfc-editor.org/info/rfc7788>.

[RFC7872] Gont, F., Linkova, J., Chown, T., and W. Liu, «Observations on the Dropping of Packets with IPv6 Extension Headers in the Real World», RFC 7872, DOI 10.17487/RFC7872, June 2016, <https://www.rfc-editor.org/info/rfc7872>.

[RFC8085] Eggert, L., Fairhurst, G., and G. Shepherd, «UDP Usage Guidelines», BCP 145, RFC 8085, DOI 10.17487/RFC8085, March 2017, <https://www.rfc-editor.org/info/rfc8085>.

[RFC8086] Yong, L., Ed., Crabbe, E., Xu, X., and T. Herbert, «GRE-in-UDP Encapsulation», RFC 8086, DOI 10.17487/RFC8086, March 2017, <https://www.rfc-editor.org/info/rfc8086>.

[RFC8100] Geib, R., Ed. and D. Black, «Diffserv-Interconnection Classes and Practice», RFC 8100, DOI 10.17487/RFC8100, March 2017, <https://www.rfc-editor.org/info/rfc8100>.

[RFC8151] Yong, L., Dunbar, L., Toy, M., Isaac, A., and V. Manral, «Use Cases for Data Center Network Virtualization Overlay Networks», RFC 8151, DOI 10.17487/RFC8151, May 2017, <https://www.rfc-editor.org/info/rfc8151>.

[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>.

[RFC8300] Quinn, P., Ed., Elzur, U., Ed., and C. Pignataro, Ed., «Network Service Header (NSH)», RFC 8300, DOI 10.17487/RFC8300, January 2018, <https://www.rfc-editor.org/info/rfc8300>.

[RFC8402] Filsfils, C., Ed., Previdi, S., Ed., Ginsberg, L., Decraene, B., Litkowski, S., and R. Shakir, «Segment Routing Architecture», RFC 8402, DOI 10.17487/RFC8402, July 2018, <https://www.rfc-editor.org/info/rfc8402>.

[RFC8445] Keranen, A., Holmberg, C., and J. Rosenberg, «Interactive Connectivity Establishment (ICE): A Protocol for Network Address Translator (NAT) Traversal», RFC 8445, DOI 10.17487/RFC8445, July 2018, <https://www.rfc-editor.org/info/rfc8445>.

[RFC8517] Dolson, D., Ed., Snellman, J., Boucadair, M., Ed., and C. Jacquenet, «An Inventory of Transport-Centric Functions Provided by Middleboxes: An Operator Perspective», RFC 8517, DOI 10.17487/RFC8517, February 2019, <https://www.rfc-editor.org/info/rfc8517>.

[RFC8557] Finn, N. and P. Thubert, «Deterministic Networking Problem Statement», RFC 8557, DOI 10.17487/RFC8557, May 2019, <https://www.rfc-editor.org/info/rfc8557>.

[RFC8568] Bernardos, CJ., Rahman, A., Zuniga, JC., Contreras, LM., Aranda, P., and P. Lynch, «Network Virtualization Research Challenges», RFC 8568, DOI 10.17487/RFC8568, April 2019, <https://www.rfc-editor.org/info/rfc8568>.

[RFC8578] Grossman, E., Ed., «Deterministic Networking Use Cases», RFC 8578, DOI 10.17487/RFC8578, May 2019, <https://www.rfc-editor.org/info/rfc8578>.

[RFC8655] Finn, N., Thubert, P., Varga, B., and J. Farkas, «Deterministic Networking Architecture», RFC 8655, DOI 10.17487/RFC8655, October 2019, <https://www.rfc-editor.org/info/rfc8655>.

[RFC8754] Filsfils, C., Ed., Dukes, D., Ed., Previdi, S., Leddy, J., Matsushima, S., and D. Voyer, «IPv6 Segment Routing Header (SRH)», RFC 8754, DOI 10.17487/RFC8754, March 2020, <https://www.rfc-editor.org/info/rfc8754>.

[SPB] «IEEE Standard for Local and metropolitan area networks — Bridges and Bridged Networks», DOI 10.1109/IEEESTD.2018.8403927, IEEE 802.1Q-2018, July 2018, <https://ieeexplore.ieee.org/document/8403927>.

[SRV6-NETWORK] Filsfils, C., Camarillo, P., Leddy, J., Voyer, D., Matsushima, S., and Z. Li, «SRv6 Network Programming», Work in Progress, Internet-Draft, draft-ietf-spring-srv6-network-programming-16, 27 June 2020, <https://tools.ietf.org/html/draft-ietf-spring-srv6-network-programming-16>.

[USER-PLANE-PROTOCOL] Homma, S., Miyasaka, T., Matsushima, S., and D. Voyer, «User Plane Protocol and Architectural Analysis on 3GPP 5G System», Work in Progress, Internet-Draft, draft-ietf-dmm-5g-uplane-analysis-03, 3 November 2019, <https://tools.ietf.org/html/draft-ietf-dmm-5g-uplane-analysis-03>.

Приложение A. Таксономия ограниченных доменов

В этом приложении рассмотрена таксономия ограниченных доменов, включая:

  • домен как целое;

  • отдельные узлы;

  • границы доменов;

  • топологию доменов;

  • технологии доменов;

  • подключение доменов к Internet

  • модели безопасности, доверия и конфиденциальности;

  • рабочие операции.

A.1. Домен как целое

  • Почему домен существует (например, человеческий выбор, административные правила, организационные требования, технические требования, такие как операционное разделение с целями масштабирования)?

  • Если есть специальные требования, они относятся к L2, L3 или вышележащему уровню?

  • Где находится домен в спектре от полностью управляемого людьми до соврешенно автономного?

  • Если домен управляемый, какой стиль применяется (ручная или автоматизированная настройка, автоматическое управление (orchestration))?

  • Имеется ли модель политики (намерения, правила настройки конфигурации)?

  • Используется в домене контролируемый, платный или свободный доступ?

A.2. Отдельные узлы

  • Являются члены домена полными узлами или только интерфейсами узлов?

  • Являются узлы постоянными членами домена или возможно подключение и отключение?

  • Являются узлы физическими или виртуальными устройствами?

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

  • Являются узлы ограниченными в возможностях (батареи и т. п.)?

  • Устройства устанавливаются «из коробки» или требуют предварительной настройки?

A.3. Граница домена

  • Как задается или идентифицируется граница домена?

  • Граница домена фиксирована или является динамической?

  • Являются граничные узлы специальными или можно применять любое устройство?

A.4. Топология

  • Является домен частью другого домена L2 или L3?

  • Перекрывается ли домен с другими доменами (может ли узел входить в несколько доменов)?

  • Модем соответствует физической топологии или использует виртуальную (наложенную)?

  • Ограничен домен зданием, кампусом, транспортным средством или является распределенным?

  • Распределенный домен имеет соединения через частные сети или Internet?

  • В плане адресации IP домен является локальным для канала, локальным для сайта или глобальным?

  • Соответствует ли область индивидуальной и групповой адресации границам домена?

A.5. Технология

  • Какие применяются протоколы маршрутизации или иные механизмы пересылки (например, MPLS или не-IP)?

  • Если домен является наложенным, какой применяется метод (L2VPN, L3VPN и т. п.)?

  • Есть ли специфические требования QoS?

  • Какова задержка на каналах — обычная или очень большая?

  • Имеются ли в домене мобильные узлы? Является ли вся сеть мобильной?

  • Какие специфические технологии применимы (например, из числа описанных в разделе 4)?

A.6. Подключение к Internet

  • Является подключение к Internet постоянным или прерывистым (отсутствие подключения не считается)?

  • Блокируется ли трафик на входе или выходе?

  • Какой трафик разрешен (allow), входящий или исходящий?

  • Какой трафик преобразуется, входящий или исходящий?

  • Нужен ли защищенный или привилегированный удаленный доступ?

  • Разрешает ли домен непривилегированные удаленные сессии?

A.7. Модель безопасности, доверия и приватности

  • Требуется ли контроль полномочий для членов домена?

  • Имеют ли все узлы домена одинаковый уровень доверия?

  • Является ли трафик аутентифицированным?

  • Шифруется ли трафик?

  • Что спрятано от внешнего мира?

A.8. Работа

  • Играет ли домен важную роль в обеспечении безопасности людей?

  • Требования к надежности обычны или нужно 99,999%?

  • Работает ли домен в условиях опасной среды?

  • Имеются ли специфические требования к установке?

  • Доступ для обслуживания — просто, сложно или невозможно?

  • Возможно ли обновление программ и микрокода?

A.9. Использование таксономии

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

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

Полезные замечания предоставили Amelia Andersdotter, Edward Birrane, David Black, Ron Bonica, Mohamed Boucadair, Tim Chown, Darren Dukes, Donald Eastlake, Adrian Farrel, Tom Herbert, Ben Kaduk, John Klensin, Mirja Kuehlewind, Warren Kumari, Andy Malis, Michael Richardson, Mark Smith, Rick Taylor, Niels ten Oever и другие.

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

Sheng Jiang

Huawei Technologies

Q14, Huawei Campus

No. 156 Beiqing Road

Hai-Dian District, Beijing

100095

China

Email: jiangsheng@huawei.com

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

Brian Carpenter

The University of Auckland

School of Computer Science

University of Auckland

PB 92019

Auckland 1142

New Zealand

Email: brian.e.carpenter@gmail.com

Bing Liu

Huawei Technologies

Q14, Huawei Campus

No. 156 Beiqing Road

Hai-Dian District, Beijing

100095

China

Email: leo.liubing@huawei.com

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

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

nmalykh@protokols.ru

1Quality-of-service — качество обслуживания.

2Supervisory Control And Data Acquisition — диспетчерское управление и сбор данных.

3Internet-of-Things — Internet вещей.

4Interactive Connectivity Establishment — интерактивная организация соединений.

5Virtual Private LAN Service — виртуальная частная ЛВС.

6Content Delivery Network — сеть доставки содержимого.

7Virtual private network — виртуальная частная сеть.

8Transparent Interconnection of Lots of Links — прозрачные соединения между большим числом каналов.

9Shortest Path Bridging — мост через кратчайший путь.

10Differentiated Services Code Point — код дифференцированного обслуживания.

11Service Function Chaining.

12Network Service Header — заголовок сетевой службы.

13Firewall and Service Ticket — квитанция (билет) для межсетевых экранов и служб.

14Home Network Control Protocol — протокол управления домашней сетью.

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

16Internet of Things — Internet вещей.

17Differentiated Services Code Point — код дифференцирования услуг.

Рубрика: RFC | Комментарии к записи RFC 8799 Limited Domains and Internet Protocols отключены

RFC 8791 YANG Data Structure Extensions

Internet Engineering Task Force (IETF)                        A. Bierman
Request for Comments: 8791                                     YumaWorks
Updates: 8340                                               M. Bjorklund
Category: Standards Track                                          Cisco
ISSN: 2070-1721                                                K. Watsen
                                                         Watsen Networks
                                                               June 2020

YANG Data Structure Extensions

Расширения структур данных YANG

PDF

Аннотация

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

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

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

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

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

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

Copyright (c) 2020. Авторские права принадлежат 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-data в RFC 8040 [RFC8040], но его функциональность ограничена.

Расширение yang-data предполагалось применять для моделирования протокольных сообщений или их частей, как в определении errors модуля YANG ietf-restconf [RFC8040] или в содержимом файла. Однако протоколы часто разделены на уровни так, что заголовок и части данных могут расширяться в дополнительных (внешних) документах. Операторы YANG, моделирующие протокол, должны поддерживать расширяемость, которая уже имеется в протоколе.

Этот документ определяет новый операторо расширения YANG structure, похожий на yang-data из [RFC8040], но более гибкий. Не принимается никаких допущения о том, что структура данных YANG может использоваться лишь как абстракция верхнего уровня и она может быть вложена в другую структуру данных.

Документ также определяет оператор расширения YANG augment-structure, позволяющий дополнять абстрактные структуры из внешних модулей и походий на имеющийся в YANG оператор augment. Отметим, что augment нельзя применять для дополнения структур данных YANG, поскольку от компиляторов YANG и иных инструментов не требуется понимать расширение structure.

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

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

YANG data structure — структура данных YANG

Структура данных, определённая с применением оператора structure.

1.1.1. NMDA

Термины, определённые в архитектуре хранилища данных сетевого управления (Network Management Datastore Architecture или NMDA) [RFC8342]:

  • configuration — конфигурация;

  • operational state — рабочее состояние.

1.1.2. YANG

Термины, определённые в [RFC7950]:

  • absolute-schema-nodeid;

  • container — контейнер;

  • data definition statement — оператор определения данных;

  • data node — узел данных;

  • leaf — лист;

  • leaf-list — лист-список;

  • list — список.

2. Определения

Структуры данных YANG определяются оператором расширения structure, определенным в модуле YANG ietf-yang-structure-ext. Аргументом structure является имя структуры данных. Принадлежность структур данных к одному идентификатору пространства имён определена в параграфе 6.2.1 [RFC7950]. В частности, там сказано (седьмой пункт):

Все узлы типа leaf, leaf-list, list, container, choice, rpc, action, notification, anydata и anyxml, определенные (напрямую или с помощью оператора uses) в родительском узле или на верхнем уровне модуля и его субмодулей, используют общее пространство имен.

Это значит, что структуры данных, определённые оператором structure, не могут иметь имя, совпадающее с именем братского (sibling) узла из обычного оператора определения данных YANG или других операторов structure в том же модуле YANG.

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

Структура данных YANG кодируется как узел anydata. Это означает, что имя структуры кодируется как контейнер (container), а дочерние экземпляры как потомки этого узла. Например, структуру

     module example-errors {
       ...

       sx:structure my-error {
         leaf error-number {
           type int;
         }
       }
     }

можно представить в JSON как

     "example-errors:my-error": {
       "error-number": 131
     }

3. Структуры данных YANG в диаграммах деревьев YANG

Структура данных YANG может быть выведена в диаграмме дерева YANG [RFC8340]. Этот документ обновляет RFC 8340 [RFC8340], определяя два новых раздела в диаграмме дерева для модуля.

  1. Структуры данных YANG смещены на 2 пробела и указываются ключевым словом structure, за которым следует имя структуры данных YANG и двоеточие (:).

  2. Дополнения структуры данных YANG, смещены на 2 пробела и указываются ключевым словом augment-structure, за которым следует имя целевой структуры расширения и двоеточие (:).

Новые разделы с учётом пробелов имеют вид

     structure <structure-name>:
       +--<node>
          +--<node>
          |  +--<node>
          +--<node>
     structure <structure-name>:
       +--<node>

     augment-structure <structure-name>:
       +--<node>
          +--<node>
          |  +--<node>
          +--<node>
     augment-structure <structure-name>:
       +--<node>

Узлы в структурах данных YANG выводятся по правилам параграфа 2.6 в [RFC8340] и не имеют флагов (<flags>).

4. Модуль расширения структур данных YANG

   <CODE BEGINS> file "ietf-yang-structure-ext@2020-06-17.yang"
   module ietf-yang-structure-ext {
     yang-version 1.1;
     namespace "urn:ietf:params:xml:ns:yang:ietf-yang-structure-ext";
     prefix sx;

     organization
       "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
     contact
       "WG Web:   <https://datatracker.ietf.org/wg/netmod/> 
        WG List:  <mailto:netmod@ietf.org> 

        Author:   Andy Bierman
                  <mailto:andy@yumaworks.com> 

        Author:   Martin Bjorklund
                  <mailto:mbj+ietf@4668.se> 

        Author:   Kent Watsen
                  <mailto:kent+ietf@watsen.net>"; 
     description
       "Этот модуль содержит концептуальные спецификации YANG для 
        определения абстрактных структур данных.

        Ключевые слова ДОЛЖНО, НЕДОПУСТИМО, ТРЕБУЕТСЯ, НУЖНО, НЕ НУЖНО, 
        СЛЕДУЕТ, НЕ СЛЕДУЕТ, РЕКОМЕНДУЕТСЯ, НЕ РЕКОМЕНДУЕТСЯ, МОЖНО,
        НЕОБЯЗАТЕЛЬНО в этом документе трактуются в соответствии с 
        BCP 14 (RFC 2119) (RFC 8174) тогда и только тогда, когда они
        указаны заглавными буквами, как показано здесь.

        Авторские права (c) 2020 IETF принадлежат IETF Trust и
        лицам, указанным как авторы. Все права защищены.
        Распространение и применение модуля в исходной или двоичной 
        форме с изменениями или без таковых разрешено в соответствии с
        лицензией Simplified BSD License, изложенной в параграфе 4.c
        IETF Trust's Legal Provisions Relating to IETF Documents
        (https://trustee.ietf.org/license-info). 
        Эта версия модуля YANG является частью RFC 8791
        (https://www.rfc-editor.org/info/rfc8791), где правовые
        аспекты приведены более полно.";
     revision 2020-06-17 {
       description
         "Исходный выпуск.";
       reference
         "RFC 8791: YANG Data Structure Extensions.";
     }

     extension structure {
       argument name {
         yin-element true;
       }
       description
         "Это расширение служит для задания структуры данных YANG, 
          представляющей концептуальные данные, определённые в YANG. 
          Оно предназначено для описания иерархических данных, независимо
          от контекста протокола и формата кодирования сообщений. Операторы
          определения данных в structure задают базовый синтаксис для 
          конкретной структуры данных YANG, именем которой служит аргумент
          оператора расширения structure.

          Отметим, что это расширение не задаёт тип носителя. Спецификация,
          использующая расширение, ДОЛЖНА задать правила кодирования 
          сообщений, включая тип носителя для содержимого, если это 
          применимо.

          Обязательный параметр name указывает определяемую структуру данных
          YANG.

          Это расширение действительно лишь как оператор верхнего уровня, 
          т. е. как субоператор в module или submodule.

          Субоператоры этого расширения ДОЛЖНЫ следовать указанным ниже 
          правилам ABNF, заданным в RFC 7950:
            *must-stmt
            [status-stmt]
            [description-stmt]
            [reference-stmt]
            *(typedef-stmt / grouping-stmt)
            *data-def-stmt

          Структура данных YANG, определяемая этим оператором расширения,
          кодируется как узел anydata. Это значит, что имя структуры
          кодируется как container с дочерними операторами, кодируемыми как
          потомки этого узла.

          Имя модуля и пространство имён модуля YANG, использующего оператор
          расширения, назначаются каждому оператору определения данных, 
          происходящему из структуры данных YANG.

          Элемент документа XPath является самим оператором расширения так, 
          что дочерние узлы элемента представляются субоператорами
          data-def-stmt в этом расширении. Этот концептуальный документ
          является контекстом для указанных ниже операторов YANG.
            - must-stmt
            - when-stmt
            - path-stmt
            - min-elements-stmt
            - max-elements-stmt
            - mandatory-stmt
            - unique-stmt
            - ordered-by
            - instance-identifier data type

          Указанные ниже субоператоры data-def-stmt ограничены при 
          использовании в операторе расширения structure:
            - в list-stmt не требуется включать key-stmt;
            - config-stmt игнорируется при наличии.
         ";
     }

     extension augment-structure {
       argument path {
         yin-element true;
       }
       description
         "Это расширение служит для дополнения структур данных YANG,
          определённых оператором structure. Оно предназначено для описания
          иерархических данных, независимо от контекста протокола и формата
          кодирования сообщений.

          Оператор имеет почти такую же структуру, как augment-stmt. 
          Операторы определения данных внутри этого оператора задают
          семантику и базовый синтаксис дополнительных данных, добавляемых
          в конкретную структуру данных YANG, указанную аргументом path.

          Обязательный параметр path указывает концептуальный узел данных 
          YANG, который будет дополнен и представлен строкой 
          absolute-schema-nodeid, где первый узел указывает дополняемую
          структуру данных YANG, а остальные узлы строки указывают узел в
          структуре YANG для дополнения.

          Это расширение действительно лишь как оператор верхнего уровня, 
          т. е. как субоператор в module или submodule.

          Субоператоры этого расширения ДОЛЖНЫ следовать указанным ниже 
          правилам ABNF, заданным в RFC 7950:
            [status-stmt]
            [description-stmt]
            [reference-stmt]
            1*(data-def-stmt / case-stmt)

          Имя модуля и пространство имён для модуля YANG, использующего
          оператор расширения назначаются документу данных экземпляра, 
          соответствующему операторам определений в этом расшинении.

          Элемент документа XPath является самим оператором расширения так, 
          что дочерние узлы элемента представляются субоператорами
          data-def-stmt в дополняемом операторе structure.

          Узел контекста оператора augment-structure выводится так же, как 
          в [RFC7950]. Этот концептуальный узел считается узлом контекста для
          перечисленных ниже операторов YANG.
            - must-stmt
            - when-stmt
            - path-stmt
            - min-elements-stmt
            - max-elements-stmt
            - mandatory-stmt
            - unique-stmt
            - ordered-by
            - instance-identifier data type

          Указанные ниже субоператоры ограничены при использовании внутри
          оператора расширения augment-structure.
            - в list-stmt не требуется включать key-stmt;
            - config-stmt игнорируется при наличии.

          Пример
             module foo {
                import ietf-yang-structure-ext { prefix sx; }

                sx:structure foo-data {
                  container foo-con { }
                }
             }

             module bar {
                import ietf-yang-structure-ext { prefix sx; }
                import foo { prefix foo; }

                sx:augment-structure /foo:foo-data/foo:foo-con {
                  leaf add-leaf1 { type int32; }
                  leaf add-leaf2 { type string; }
                }
             }
         ";
     }
   }
   <CODE ENDS>

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

5.1. Реестр YANG Module

Агентство IANA зарегистрировало указанный ниже идентификатор URI в субреестре ns реестра IETF XML [RFC3688].

URI: urn:ietf:params:xml:ns:yang:ietf-yang-structure-ext

Registrant Contact: The IESG.

XML: N/A; запрошенный идентификатор URI относится к пространству имён XML.

Агентство IANA зарегистрировало указанный ниже модуль YANG в субреестре YANG Module Names [RFC6020] реестра YANG Parameters.

Name: ietf-yang-structure-ext

Namespace: urn:ietf:params:xml:ns:yang:ietf-yang-structure-ext

Prefix: sx

Reference: RFC 8791

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

Этот документ определяет расширения YANG, служащие для определения концептуальных структур данных YANG. Он не создаёт новых уязвимостей в дополнение к имеющимся в YANG 1.1 [RFC7950].

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

7.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>.

[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>.

[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>.

[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, <http://www.w3.org/TR/2008/REC-xml-20081126>.

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

[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>.

Приложение A. Примеры

A.1. structure

Этот пример показывает простую адресную книгу, которую можно сохранить.

   module example-module {
     yang-version 1.1;
     namespace "urn:example:example-module";
     prefix exm;

     import ietf-yang-structure-ext {
       prefix sx;
     }

     sx:structure address-book {
       list address {
         key "last first";
         leaf last {
           type string;
           description "Фамилия";
         }
         leaf first {
           type string;
           description "Имя";
         }
         leaf street {
           type string;
           description "Улица";
         }
         leaf city {
           type string;
           description "Город";
         }
         leaf state {
           type string;
           description "Штат";
         }
       }
     }
   }

Ниже представлена диаграмма дерева для модуля.

   module: example-module

     structure address-book:
       +-- address* [last first]
          +-- last      string
          +-- first     string
          +-- street?   string
          +-- city?     string
          +-- state?    string

A.2. augment-structure

Этот пример добавляет листья county и zipcode в книгу адресов.

   module example-module-aug {
     yang-version 1.1;
     namespace "urn:example:example-module-aug";
     prefix exma;

     import ietf-yang-structure-ext {
       prefix sx;
     }
     import example-module {
       prefix exm;
     }

     sx:augment-structure "/exm:address-book/exm:address" {
       leaf county {
         type string;
         description "Государство";
       }
       leaf zipcode {
         type string;
         description "Почтовый индекс";
       }
     }
   }

Ниже представлена диаграмма дерева для модуля.

   module: example-module-aug

     augment-structure /exm:address-book/exm:address:
       +-- county?    string
       +-- zipcode?   string

A.3. Кодирование XML

Этот пример показывает, как можно закодировать адресную книгу в XML [W3C.REC-xml-20081126].

   <address-book xmlns="urn:example:example-module">
     <address>
       <last>Flintstone</last>
       <first>Fred</first>
       <street>301 Cobblestone Way</street>
       <city>Bedrock</city>
       <zipcode xmlns="urn:example:example-module-aug">70777</zipcode>
     </address>
     <address>
       <last>Root</last>
       <first>Charlie</first>
       <street>4711 Cobblestone Way</street>
       <city>Bedrock</city>
       <zipcode xmlns="urn:example:example-module-aug">70777</zipcode>
     </address>
   </address-book>

A.4. Кодирование JSON

Этот пример показывает, как можно закодировать адресную книгу в JSON.

   "example-module:address-book": {
     "address": [
       {
         "city": "Bedrock",
         "example-module-aug:zipcode": "70777",
         "first": "Fred",
         "last": "Flintstone",
         "street": "301 Cobblestone Way"
       },
       {
         "city": "Bedrock",
         "example-module-aug:zipcode": "70777",
         "first": "Charlie",
         "last": "Root",
         "street": "4711 Cobblestone Way"
       }
     ]
   }

A.5. Пример structure с определение структуры не верхнего уровня

Приведённый ниже пример определяет структуру данных с информацией об ошибках, которую можно включить в элемент <error-info> для <rpc-error>.

   module example-error-info {
     yang-version 1.1;
     namespace "urn:example:example-error-info";
     prefix exei;

     import ietf-yang-structure-ext {
       prefix sx;
     }

     sx:structure my-example-error-info {
       leaf error-code {
         type uint32;
       }
     }

   }

Следующий пример показывает использование этой структуры в <rpc-error>.

   <rpc-reply message-id="101"
        xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
     <rpc-error>
       <error-type>protocol</error-type>
       <error-tag>operation-failed</error-tag>
       <error-severity>error</error-severity>
       <error-info>
         <my-example-error-info
             xmlns="urn:example:example-error-info">
           <error-code>42</error-code>
         </my-example-error-info>
       </error-info>
     </rpc-error>
   </rpc-reply>

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

Andy Bierman

YumaWorks

Email: andy@yumaworks.com

Martin Bjorklund

Cisco

Email: mbj+ietf@4668.se

Kent Watsen

Watsen Networks

Email: kent+ietf@watsen.net


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

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

nmalykh@protokols.ru

1Internet Engineering Task Force — комиссия по решению инженерных задач Internet.

2Internet Engineering Steering Group — комиссия по инженерным разработкам Internet.

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

Спецификация языка P4_16, версия 1.2.1

The P416 Language Specification
version 1.2.1
The P4 Language Consortium
2020-06-11

PDF

Аннотация

P4 — язык программирования для уровня данных сетевых устройств. В этом документе приведено точное определение языка P416, который является результатом пересмотра в 2016 г. языка P4 (http://p4.org). Документ предназначен для разработчиков, создающих компиляторы, имитаторы, среды разработки (IDE) и отладчики для программ P4. Документ может также быть интересен программистам P4, желающим более глубоко понять синтаксис и семантику языка.

1. Сфера применения

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

Документ не задает:

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

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

2. Термины, определения, символы

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

Architecture — архитектура

Набор программируемых на P4 компонентов и интерфейсов уровня данных между ними.

Control plane — уровень (плоскость) управления

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

Data plane — уровень (плоскость) данных

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

Metadata — метаданные

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

Packet — пакет

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

Packet header — заголовок пакета

Форматированные данные в начале пакета. Пакет может содержать последовательность заголовков, представляющих различные сетевые протоколы.

Packet payload — данные пакета

Данные, следующие после заголовков пакета.

Packet-processing system — система обработки пакетов

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

Target — целевая платформа (цель)

Система обработки пакетов, способная выполнять программы P4.

Термины, определенные в этом документе, не следует трактовать как косвенно связанные с ними термины других документов. И наоборот, не определенные здесь термины следует интерпретировать в соответствии с общепризнанными источниками, такими как IETF RFC.

3. Обзор

   Рисунок 1. Традиционные и программируемые коммутаторы.

P4 представляет собой язык, описывающий обработку пакетов в плоскости данных программируемого элемента пересылки, такого как программный или аппаратный коммутатор, сетевой адаптер, маршрутизатор или специализированная сетевая платформа. Имя P4 возникло из названия статьи, где язык был предложен — «Programming Protocol-independent Packet Processors»1. Хотя P4 изначально был предназначен для программируемых коммутаторов, область его применения расширилась и сейчас охватывает широкий спектр устройств. В оставшейся части документа такие устройствами будут называться целевыми платформами или целями (target).

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

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

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

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

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

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

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

  • Синтаксические анализаторы (parser) описывают разрешенные последовательности заголовков в принимаемых пакетах, идентификацию таких последовательностей, а также заголовки и поля для извлечения из пакетов.

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

  • Действия — фрагменты кода, описывающие манипуляции с полями пакета и метаданными. Действия могут включать данные, представленные плоскостью управления в процессе работы.

  • Блоки «сопоставление-действие» (СД), выполняющие ряд операций:

    • создание ключей поиска из полей пакета или рассчитанных метаданных;

    • поиск в таблицах по созданным ключам и выбор выполняемых действий (включая связанные данные);
    • выполнение выбранного действия.

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

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

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

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

Рисунок 2. Программирование с использованием P4.

На рисунке 2 показан типовой процесс программирования целевой платформы с использованием P4.

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

Компиляция набора программ P4 создает:

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

  • API для управления состояниями объектов уровня данных из плоскости управления.

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

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

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

3.1. Преимущества P4

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

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

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

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

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

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

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

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

3.2. Развитие P4 (сравнение с P4 v1.0/v1.1)

По сравнению с P414 (ранняя версия языка) P416 включает множество важных, но несовместимых изменений в синтаксисе и семантике. Развитие от P414 к P416 показано на рисунке 3. В частности, многие функции (включая счетчики, расчет контрольных сумм, измерители и т. п.) были перенесены из основного языка в библиотеки.

Рисунок 3. Развитие языка P4.

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

В версии 1.1 языка P4 добавлена конструкция extern, которую можно применять для описания библиотечных элементов. Многие конструкции в спецификации v1.1 были преобразованы в библиотечные элементы (включая исключенные из языка конструкции, такие как счетчики и измерители). Ожидается, что некоторые из этих внешних объектов будут стандартизованы и включены потом в новый документ, описывающий библиотечные элементы P4. В этом документе рассматривается несколько примеров внешних конструкций. P416 также вводит и меняет некоторые языковые конструкции v1.1 для описания программируемых частей архитектуры (parser, state, control, package).

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

4. Архитектурная модель

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

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

Рисунок 4. Программные интерфейсы P4.

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

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

Рисунок 5. Программа P4, вызывающая службы объекта с фиксированными функциями.

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

4.1. Стандартные архитектуры

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

4.2. Интерфейсы уровня данных

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

control MatchActionPipe<H>(in bit<4> inputPort,
				inout H parsedHeaders,
				out bit<4> outputPort);

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

  • Первым параметром является 4-битовое значение inputPort. Направление in показывает, что это входной параметр, который не может быть изменен в блоке.

  • Вторым параметром является объект типа H с именем parsedHeaders, где H — переменная типа, представляющая заголовки, которые будут далее определены программистом P4. Направление inout показывает, что параметр является сразу входным и выходным.

  • Третьим параметром является 4-битовое значение outputPort. Направление out указывает выходной параметр, начальное значение которого не определено, но параметр можно изменять.

4.3. Внешние объекты и функции

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

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

extern Checksum16 {
	Checksum16();		// конструктор
	void clear();		// подготовка к расчету
	void update<T>(in T data); // добавление данных в контрольную сумму
	void remove<T>(in T data); // исключение данных из контрольной суммы
	bit<16> get(); 	// получение контрольной суммы для данных, добавленных после  					
                        // предшествующего сброса (clear)
}

5. Пример очень простого коммутатора

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

Рисунок 6. Архитектура очень простого коммутатора.

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

VSS принимает пакеты через один из 8 входных портов Ethernet, канал рециркуляции или порт, подключенный напрямую к CPU. VSS имеет один синтаксический анализатор в единственном конвейере СД, связанном с единственным сборщиком (deparser). После выхода из сборщика пакет передается в один из 8 выходных портов Ethernet или в один из трех специальных портов:

  • CPU для передачи плоскости управления;

  • Drop в случае отбрасывания пакета;

  • Recirculate для повторного прохождения через коммутатор.

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

5.1. Архитектура VSS

Приведенная ниже программа P4 объявляет VSS, как это мог сделать производитель. Задано несколько типов, констант и 3 программируемых блока, описанных типами и реализованных программой коммутатора.

// Файл "very_simple_switch_model.p4"
// Объявление в VSS основной библиотеки P4 требуется
// для определений packet_in и packet_out.
# include <core.p4>
/* Объявления констант и структур */
/* Порты представляются 4-битовыми значениями */
typedef bit<4> PortId;
/* Имеется лишь 8 реальных портов */
const PortId REAL_PORT_COUNT = 4w8;	// 4w8 - 8 в 4-битовом формате
/* Метаданные, сопровождающие входной пакет */
struct InControl {
	PortId inputPort;
}
/* Специальные значения для входных портов */
const PortId RECIRCULATE_IN_PORT = 0xD;
const PortId CPU_IN_PORT = 0xE;
/* Метаданные, которые должны создавать для выходных пакетов */
struct OutControl {
	PortId outputPort;
}
/* Специальные значения для выходных портов */
const PortId DROP_PORT = 0xF;
const PortId CPU_OUT_PORT = 0xE;
const PortId RECIRCULATE_OUT_PORT = 0xD;
/* Прототипы программируемых блоков */
/**
* Программируемый анализатор.
* @param <H> - тип заголовка, задаваемый пользователем
* @param b - входной пакет
* @param parsedHeaders - заголовки, созданные анализатором
*/
parser Parser<H>(packet_in b, out H parsedHeaders);
/**
* Конвейер «сопоставление-действие»
* @param <H> - тип входных и выходных заголовков
* @param headers - заголовки, полученные от анализатора и отправляемые сборщику
* @param parseError - ошибки, которые могут возникать при анализе
* @param inCtrl - информация от архитектуры, сопровождающая входной пакет
* @param outCtrl - информация для архитектуры, сопровождающая выходной пакет
*/
control Pipe<H>(inout H headers,
			in error parseError,	// ошибка анализатора
			in InControl inCtrl,	// входной порт
			out OutControl outCtrl); 	// выходной порт
/**
* Сборщик VSS.
* @param <H> - тип заголовков, задаваемый пользователем
* @param b - выходной пакет
* @param outputHeaders - заголовки для выходного пакета
*/
control Deparser<H>(inout H outputHeaders, packet_out b);
/**
* Объявление пакета верхного уровня. Должен создаваться пользователем.
* Аргументы задают блоки, которые должен создать пользователь.
* @param <H> - заданный пользователем тип обрабатываемых заголовков.
*/
package VSS<H>(Parser<H> p,
			Pipe<H> map,
			Deparser<H> d);
// Зависимые от архитектуры объекты, которые могут создаваться.
// Блок контрольных сумм.
extern Checksum16 {
	Checksum16();			// конструктор
	void clear();			// подготовка к расчету
	void update<T>(in T data);	// добавление данных в контрольную сумму
	void remove<T>(in T data);	// исключение данных из контрольной суммы
	bit<16> get(); 		// контрольная сумма для данных после clear
}

Рассмотрим некоторые из элементов.

  • Файл core.p4 (Приложение D. Основная библиотека P4) определяет стандартные типы данных и коды ошибок.

  • Тип bit<4> указывает строку из 4 битов.

  • Синтаксис 4w0xF указывает значение 15, представленное 4 битами. Другим вариантом записи является 4w15. Во многих случаях указатель размера можно опустить, просто написав 15.

  • Тип error является встроенным типом P4 для кодов ошибок.

Далее приведено объявление синтаксического анализатора

parser Parser<H>(packet_in b, out H parsedHeaders);

Это объявление описывает интерфейс анализатора, но не содержит его реализации, которую предоставляет программист. Анализатор читает данные из packet_in (предопределенный внешний объект P4 для представления входящего пакета, объявленный в библиотеке core.p4). Анализатор записывает свой вывод (ключевое слово out) в аргумент parsedHeaders. Тип этого аргумента H еще не известен и будет задан программистом.

Объявление

control Pipe<H>(inout H headers,
		in error parseError,
		in InControl inCtrl,
		out OutControl outCtrl);

описывает интерфейс конвейера СД (Match-Action) с именем Pipe. Конвейер принимает на входе заголовки headers, параметр для ошибок parseError и данные управления inCtrl. На рисунке 6 показаны источники этих данных. Конвейер записывает свой вывод в outCtrl и должен обновить заголовки, передаваемые сборщику.

Пакет верхнего уровня называется VSS и для программирования VSS пользователь должен создать экземпляр пакета этого типа (см. ниже). Объявление пакета верхнего уровня зависит от типа переменной H

package VSS<H>

Переменная типа указывает тип, который еще не известен и должен быть предоставлен пользователем позже. В данном случае H является типом набора заголовков, который пользовательская программа будет обрабатывать. Анализатор будет выдавать разобранное представления этих заголовков, а конвейер СД будет обновлять входные заголовки, заменяя их выходными.

Объявление пакета VSS включает три составных параметра типов Parser, Pipe и Deparser, которые являются объявлениями, описанными здесь. Для программирования платформы нужно представить значения этих параметров.

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

5.2. Описание архитектуры VSS

Для полного понимания поведения VSS и создания осмысленных программ P4 для нее, а также реализации плоскости управления нужно полностью описать блоки с фиксированной функциональностью. Ниже рассматривается простой пример, иллюстрирующий все детали, которые нужно учитывать при описании архитектуры. Язык P4 не предназначен для описания всех функциональных блоков — он может лишь описать взаимодействие между программируемыми блоками и архитектурой. Для текущей программы этот интерфейс задается объявлениями блоков Parser, Pipe и Deparser. На практике предполагается полное описание архитектуры в виде исполняемой программы и/или схем и текста. В этом документе приводится неформальное текстовое описание.

5.2.1. Блок арбитража

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

  • Прием пакета от одного из физических портов Ethernet, плоскости управления или порта рециркуляции.

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

  • Прием пакета запускает механизм арбитража, если доступно несколько пакетов.

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

  • После получения пакета блок арбитража устанавливает значение inCtrl.inputPort, являющееся входным для конвейера СД, и указывает принявший порт пакет. Физические порты Ethernet имеют номера от 0 до 7, порт рециркуляции — 13, а порт CPU — 14.

5.2.2. Блок выполнения синтаксического анализа

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

5.2.3. Блок демультиплексора

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

  • Отправка пакета в порт drop вызывает исчезновение пакета.

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

  • Отправка пакета в выходной порт CPU ведет к передаче пакета плоскости управления. Процессору передается исходный полученный пакет, а не результат работы сборщика (тот просто отбрасывается).

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

  • Если пакет имеет некорректное значение outputPort (например, 9), он отбрасывается.

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

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

5.2.4. Доступные внешние блоки

Архитектура VSS включает внешний блок инкрементного расчета контрольных сумм Checksum16, имеющий конструктор и 4 метода:

  • clear() готовит блок к новому расчету;

  • update<T>(in T data) добавляет данные в расчет контрольной суммы (данные должны быть строкой битов, заголовком или структурой с такими значениями), указанные поля добавляются (конкатенация) в порядке их задания в объявлении типа;

  • get() возвращает 16-битовую контрольную сумму с дополнением до 1, при вызове этой функции блок контрольных сумм должен получать целое число байтов данных;

  • remove<T>(in T data) удаляет из расчета данные, которые раньше учитывались в контрольной сумме.

5.3. Полная программа VSS

Здесь представлена полна реализация программы P4 для базовой пересылки пакетов IPv4 на платформе VSS. Программа не использует все возможности архитектуры (например, рециркуляцию), по применяет директивы препроцессора #include (6.2. Предварительная обработка).

Синтаксический анализатор пытается распознать заголовок Ethernet, за которым следует заголовок IPv4. Если любой из этих заголовков отсутствует, анализ завершается ошибкой. В остальных случаях информация из заголовков извлекается в структуру Parsed_packet. Конвейер СД, показанный на рисунке 7, включает 4 блока СД (ключевое слово P4 table).

  • При возникновении ошибки в анализаторе пакет отбрасывается (outputPort = DROP_PORT).

  • Первая таблица использует адрес получателя IPv4 для определения outputPort и адреса IPv4 следующего узла пересылки. Если поиск не дал результата, пакет отбрасывается. Таблица также декрементирует IPv4 ttl.

  • Вторая таблица проверяет значение ttl и при обнаружении 0 передает пакет плоскости управления через порт CPU.

  • Третья таблица использует адрес IPv4 следующего интервала (результат первой таблицы) для определения Ethernet-адреса следующего интервала.

  • Последняя таблица использует outputPort для определения Ethernet-адреса (MAC) отправителя в текущем коммутаторе, который помещается в выходной пакет.

Рисунок 7. Схема конвейера СД, выраженного программой P4 VSS.

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

// Включение основной библиотеки P4
# include <core.p4>
// Включение объявлений архитектуры VSS.
# include "very_simple_switch_model.p4"
// Эта программа обрабатывает пакеты с заголовками Ethernet и IPv4,
// пересылая их по IP-адресу получателя.
typedef bit<48>	EthernetAddress;
typedef bit<32>	IPv4Address;
// Стандартный заголовок Ethernet
header Ethernet_h {
	EthernetAddress dstAddr;
	EthernetAddress srcAddr;
	bit<16>	etherType;
}
// заголовок IPv4 (без опций)
header IPv4_h {
	bit<4>		version;
	bit<4>		ihl;
	bit<8>		diffserv;
	bit<16>	totalLen;
	bit<16>	identification;
	bit<3>		flags;
	bit<13>	fragOffset;
	bit<8>		ttl;
	bit<8>		protocol;
	bit<16>	hdrChecksum;
	IPv4Address	srcAddr;
	IPv4Address	dstAddr;
}
// Структура проанализированных заголовков
struct Parsed_packet {
	Ethernet_h 	ethernet;
	IPv4_h		ip;
}
// Раздел анализатора
// Заданные пользователем ошибки, которые могут возникать при анализе
error {
	IPv4OptionsNotSupported,
	IPv4IncorrectVersion,
	IPv4ChecksumError
}
parser TopParser(packet_in b, out Parsed_packet p) {
Checksum16() ck;	// Создание экземпляра блока контрольных сумм
	state start {
		b.extract(p.ethernet);
		transition select(p.ethernet.etherType) {
			0x0800: parse_ipv4;
			// Нет принятого по умолчанию правила — все прочие пакеты отвергаются
		}
	}

	state parse_ipv4 {
		b.extract(p.ip);
		verify(p.ip.version == 4w4, error.IPv4IncorrectVersion);
		verify(p.ip.ihl == 4w5, error.IPv4OptionsNotSupported);
		ck.clear();
		ck.update(p.ip);
		// Проверка нулевого значения контрольной суммы
		verify(ck.get() == 16w0, error.IPv4ChecksumError);
		transition accept;
	}
}
// Раздел конвейера СД
control TopPipe(inout Parsed_packet headers,
			in error parseError, // ошибка анализатора
			in InControl inCtrl, // входной порт
			out OutControl outCtrl) {
	IPv4Address nextHop;	// локальная переменная
	/**
	* Указывает отбрасывание пакета установкой выходного порта DROP_PORT
	*/
	action Drop_action() {
		outCtrl.outputPort = DROP_PORT;
	}
	/**
	* Установка следующего интервала и выходного порта.
	* Декременитирование поля IPv4 ttl.
	* @param ivp4_dest - адрес IPv4 следующего интервала
	* @param port - выходной порт
	*/
	action Set_nhop(IPv4Address ipv4_dest, PortId port) {
		nextHop = ipv4_dest;
		headers.ip.ttl = headers.ip.ttl - 1;
		outCtrl.outputPort = port;
	}
	/**
	* Расчет адреса следующего интервала IPv4 и выходного порта
	* на основе адреса получателя IPv4 в текущем пакете.
	* Декременитирование поля IPv4 TTL.
	* @param nextHop - адрес IPv4 следующего интервала
	*/
	table ipv4_match {
		key = { headers.ip.dstAddr: lpm; }	// самый длинный совпадающий префикс
		actions = {
			Drop_action;
			Set_nhop;
		}
		size = 1024;
		default_action = Drop_action;
	}
	/**
	* Передача пакета в порт CPU
	*/
	action Send_to_cpu() {
		outCtrl.outputPort = CPU_OUT_PORT;
	}
	/**
	* Проверка TTL и отправка в CPU при значении 0
	*/
	table check_ttl {
		key = { headers.ip.ttl: exact; }
		actions = { Send_to_cpu; NoAction; }
		const default_action = NoAction; // определено в core.p4
	}
	/**
	* Установка MAC-адреса получателя пакета
	* @param dmac - MAC-адрес получателя.
	*/
	action Set_dmac(EthernetAddress dmac) {
		headers.ethernet.dstAddr = dmac;
	}
	/**
	* Установка адреса Ethernet получателя пакета
	* по IP-адресу следующего интервала.
	* @param nextHop - адрес IPv4 следующего интервала.
	*/
	table dmac {
		key = { nextHop: exact; }
		actions = {
			Drop_action;
			Set_dmac;
		}
		size = 1024;
		default_action = Drop_action;
	}
	/**
	* Установка MAC-адреса отправителя.
	* @param smac - MAC-адрес отправителя
	*/
	action Set_smac(EthernetAddress smac) {
		headers.ethernet.srcAddr = smac;
	}
	/**
	* Установка MAC-адреса отправителя по выходному порту.
	*/
	table smac {
		key = { outCtrl.outputPort: exact; }
		actions = {
			Drop_action;
			Set_smac;
		}
		size = 16;
		default_action = Drop_action;
	}
	apply {
		if (parseError != error.NoError) {
			Drop_action();	// вызов drop напрямую
			return;
		}
		ipv4_match.apply(); // Результатом совпадений будет переход к nextHop
		if (outCtrl.outputPort == DROP_PORT) return;
		check_ttl.apply();
		if (outCtrl.outputPort == CPU_OUT_PORT) return;
		dmac.apply();
		if (outCtrl.outputPort == DROP_PORT) return;
		smac.apply();
	}
}
// Раздел сборщика
control TopDeparser(inout Parsed_packet p, packet_out b) {
	Checksum16() ck;
	apply {
		b.emit(p.ethernet);
	if (p.ip.isValid()) {
		ck.clear();			// Подготовка блока контрольных сумм
		p.ip.hdrChecksum = 16w0; 	// Очистка контрольной суммы
		ck.update(p.ip);		// Расчет новой контрольной суммы
		p.ip.hdrChecksum = ck.get();
	}
	b.emit(p.ip);
// Создание экземпляра пакета VSS.
VSS(TopParser(),
	TopPipe(),
	TopDeparser()) main;

6. Определение языка P4

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

  • Базовый язык, включающий типы, переменные, области действия, объявления, операторы, выражения и т. д.

  • Субязык для задания анализаторов на основе конечного автомата или машины состояний (12. Анализ пакета).

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

  • Субязык описания архитектуры (16. Описание архитектуры).

6.1. Синтаксис и семантика

6.1.1. Грамматика

Полная грамматика P416 описана в Приложении H на основе языка описания грамматики Yacc/Bison, используемого и в данном тексте. В выдержках из грамматики принимается несколько стандартных допущений:

  • для обозначения терминальных символов применяются ЗАГЛАВНЫЕ буквы;

  • применяется нотация BNF, как показано ниже

p4program
	: /* пусто */
	| p4program declaration
	| p4program ';'
	;

Псевдокод, применяемый в основном для описания семантики конструкций P4, выводится фиксированным шрифтом

ParserModel.verify(bool condition, error err) {
	if (condition == false) {
		ParserModel.parserError = err;
		goto reject;
	}
}

6.1.2. Семантика и абстрактные машины P4

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

Компиляторы P4 могут сами организовывать создаваемый код, если видимое извне поведение программ P4 соответствует данной спецификации. Таким внешним поведением считается:

  • поведение операций ввода и вывода всех блоков P4;

  • состояния, поддерживаемые внешними (extern) блоками.

6.2. Предварительная обработка

Для сборки программ из нескольких исходных файлов P4 компиляторам следует поддерживать некоторые функции препроцессоров C:

  • #define для определения макросов (без аргументов);

  • #undef;

  • #if #else #endif #ifdef #ifndef #elif;

  • #include.

Препроцессору также следует удалять символы \ и перевода строки (ASCII 92, 10), используемые для разбиения строк с целью удобочитаемости.

Могут поддерживаться другие возможности препроцессора C (например, макросы с параметрами), но это не гарантируется. Как в C, директива #include может задавать имя файла в угловых скобках или двойных кавычках.

# include <system_file>
# include "user_file"

Разница заключается в порядке поиска файлов препроцессором при неполном указании пути.

Компиляторам P4 следует корректно обрабатывать директивы #line, которые могут генерироваться в процессе предварительной обработки. Это позволяет собирать программы P4 из множества файлов:

  • базовая библиотека P4, определенная в этом документе;

  • архитектура, определяющая интерфейсы плоскости данных и блоки extern;

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

  • программы P4, задающие поведение каждого программируемого блока.

6.2.1. Основная библиотека P4

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

# include <core.p4>

6.3. Лексические конструкции

Все ключевые слова P4 содержат только символы ASCII, это же должно выполняться для всех идентификаторов P4. Компиляторам P4 следует корректно обрабатывать строки, содержащие 8-битовые символы в комментариях и строковых литералах. Язык P4 различает регистр символов. Пробельные символы, включая новую строку, считаются разделителями. Отступ от начала строки не регламентируется, однако P4 включает блочные конструкции в стиле Cи во всех примерах этого документа используются отступы в стиле C. Символы табуляции трактуются как пробелы.

Лексер распознает перечисленные ниже терминалы.

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

  • Идентификатор типа (TYPE_IDENTIFIER) указывает имя типа.

  • INTEGER означает целочисленные литералы.

  • DONTCARE — одиночный символ подчеркивания.

  • Ключевые слова (например, RETURN). По соглашению каждый терминал ключевого слова соответствует ключевому слову языка с таким же произношением, но в символах нижнего регистра. Например, терминал RETURN соответствует ключевому слову return.

6.3.1. Идентификаторы

Идентификаторы P4 могут включать лишь буквы, цифры и символы подчеркивания, а начинаться должны с буквы или подчеркивания. Специальный идентификатор _ зарезервирован для значения, которое «не имеет значения» (don’t care), а его тип может зависеть от контекста. Некоторые ключевые слова (например, apply) могут использоваться как идентификаторы, если контекст не позволяет путаницы.

nonTypeName
	: IDENTIFIER
	| APPLY
	| KEY
	| ACTIONS
	| STATE
	| ENTRIES
	| TYPE
	;

name
	:|;
	nonTypeName
	TYPE_IDENTIFIER

6.3.2. Комментарии

P4 поддерживает несколько типов комментариев:

  • однострочный комментарий от символов // до конца строки;

  • многострочный комментарий между символами /* и */, вложенные многострочные комментарии не поддерживаются;

  • комментарии в стиле Javadoc между символами /** и */.

Настоятельно не рекомендуется применять комментарии Javadoc в таблицах и действиях, используемых при создании интерфейса с плоскостью управления.

P4 считает комментарии разеделителями и не допускает комментариев внутри маркера (token). Например, bi/**/t будет рассматриваться как два маркера bi и t, а не bit.

6.3.3. Литеральные константы

6.3.3.1. Логические литералы

Для логических (Boolean) значений поддерживаются константы true и false.

6.3.3.2. Целочисленные литералы

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

  • 0x или 0X — шестнадцатеричные значения;
  • 0o или 0O — восьмеричные значения;
  • 0d или 0D — десятичные значения;
  • 0b или 0B — двоичные значения.

Размер числового литерала в битах можно задать целым числом без знака с индикатором знака:

  • w — целое число без знака;

  • s — целое число со знаком.

Отметим, что 0 в начале сам по себе не указывает восьмеричную константу. Символ _ допускается в числовых литералах, но игнорируется при определении значения анализируемого числа. Это позволяет сделать длинные числовые константы более читаемыми. Этот символ не допускается в константах указания размера и не может быть первым символом числового литерала. Внутри литералов не допускаются комментарии и пробелы.

32w255			// 32-битовое число без знака со значением 255
32w0d255		// то же самое
32w0xFF		// то же самое
32s0xFF		// 32-битовое число со знаком и значением 255
8w0b10101010		// 8-битовое число без знака со значением 0xAA
8w0b_1010_1010	// то же самое
8w170			// то же самое
8s0b1010_1010		// 8-битовое число со знаком и значением -86
16w0377		// 16-битовое число без знака со значением 377 (не 255!)
16w0o377		// 16-битовое число без знака со значением 255 (основание 8)
6.3.3.3. Строковые литералы

Строковые литералы (строки констант) задаются в форме произвольных последовательностей 8-битовых символов, заключенных в двойные кавычки («, ASCII 34). Строка начинается с символа двойных кавычек и завершается на первом символе двойных кавычек, которому не предшествует нечетное число символов \ (ASCII 92). P4 не проверяет корректность строк (т. е., допустимость использованной кодировки UTF-8).

Поскольку в P4 не поддерживаются операции над строками, строковые литералы, включая завершающие кавычки, обычно пропускаются компилятором P4 без изменений другим сторонним инструментам или backend-компиляторам. Эти инструменты могут по-своему обрабатывать escape-последовательности (например, способ задания символов Unicode или обработку непечатаемых символов ASCII).

Ниже приведено 3 примера строковых литералов.

"simple string"
"string \" with \" embedded \" quotes"
"string with embedded
line terminator"

6.4. Соглашения об именовании

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

Ниже приведены принятые в документе соглашения об именовании.

  • Встроенные типы указываются символами нижнего регистра (например, int<20>).

  • Пользовательские типы включают заглавные буквы (например, IPv4Address).

  • Переменные типов всегда указываются заглавными буквами (например, parser P<H, IH>()).

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

  • Константы указываются заглавными буквами (например CPU_PORT).

  • Ошибки и перечисляемые указываются в стиле «верблюда» (camel-case), например PacketTooShort.

6.5. Программы P4

Программа P4 представляет собой список объявлений

p4program
	: /* пусто */
	| p4program declaration
	| p4program ';'	/* пустое объявление */
	;
declaration
	: constantDeclaration
	| externDeclaration
	| actionDeclaration
	| parserDeclaration
	| typeDeclaration
	| controlDeclaration
	| instantiation
	| errorDeclaration
	| matchKindDeclaration
	| functionDeclaration
	;

Пустое объявление указывается символом ; (пустые объявления поддерживаются с учетом привычек программистов C/C++ и Java, хотя в некоторых конструкциях, например, struct, точка с запятой в конце не требуется).

6.5.1. Область действия

Некоторые конструкции P4 действуют как пространства имен, создающие локальную область действия имен, включая:

  • объявления производных типов (struct, header, header_union, enum) с локльной значимостью имен полей;

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

  • блоки parser, table, action, control с локальной областью действия;

  • объявления с переменными типов, создающими для переменных новые области действия; например, в приведенном ниже объявлении extern область действия типа H завершается в конце определения

extern E<H>(/* параметры опущены */) {/* тело опущено */} // область действия H кончается тут.

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

6.5.2. Элементы с состоянием

Большинство конструкций P4 не имеет состояний — результат работы конструкции определяется исключительно входными данными. Имеется лишь две конструкции с состояниями, сохраняющими информацию от пакета к пакету:

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

  • внешние объекты могут иметь состояния, доступные для чтения и записи плоскостям управления и данных; все конструкции из P414, сохраняющие состояние (например, счетчики, измерители, регистры), представлены в P416 объектами extern.

В P4 все элементы с состояниями должны явно выделяться при компиляции путем создания «экземпляров». Кроме того, анализаторы, блоки управления и пакеты могут создавать экземпляры элементов с состояниями. Такие элементы также должны создаваться до использования, даже если они исходно не имеют состояний. Однако таблицы не создаются заранее, хотя у них и есть состояния, — создание экземпляра таблицы происходит при ее объявлении. Это сделано для поддержки общего случая, поскольку большинство таблиц используется лишь однократно. Для более точного контроля за состоянием таблиц программистам следует объевлять их в элементах управления.

В примере параграфа 5.3. Полная программа VSS TopParser, TopPipe, TopDeparser, Checksum16 и Switch являются типами. Имеется два экземпляра Checksum16, по одному в TopParser и TopDeparser (обозначены ck). Экземпляры TopParser, TopDeparser, TopPipe и Switch создаются в конце программы в объявлении основного объекта, который является экземпляром типа Switch (пакет).

6.6. Выражения для левой части

Выражениями для левой части (l-value) считаются выражения слева от оператора присваивания или аргументы параметров функций out и inout. Эти значения являются ссылками на хранилище. Корректные варианты приведены ниже.

prefixedNonTypeName
	: nonTypeName
	| dotPrefix nonTypeName
	;
lvalue
	: prefixedNonTypeName
	| lvalue '.' member
	| lvalue '[' expression ']'
	| lvalue '[' expression ':' expression ']'
	;
  • Идентификаторы базовых и производных типов.

  • Операции доступа к элементам структур, заголовков и объединений заголовков (нотация с точками).

  • Ссылки на элементы стека заголовков (8.17. Операции над стеком заголовков) — индексация и ссылки на последний или следующий элемент.

  • Результат оператора «нарезки» битов [m:l].

Примером корректного выражения может служить headers.stack[4].field. Отметим, что вызовы методов и функций не могут возвращать l-value.

6.7. Соглашения о вызовах

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

  • используются именованные и типизованные параметры;

  • создается новая локальная область действия для параметров и локальных переменных;

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

Вызовы осуществляются с использованием семантики copy-in/copy-out. Каждый параметр помечается направлением.

  • Параметры in доступны лишь для чтения и указание такого параметра в левой части оператора присваивания или передача вызываемому не в качестве аргумента in приведет к ошибке. Параметры in инициализируются путем копирования значения соответствующего аргумента при выполнении вызова.

  • Параметры out за исключением нескольких указанных ниже случаев, инициализируются и трактуются как l-value (6.6. Выражения для левой части) в теле методов и функций. Аргументы, передаваемые как параметры out, должны быть l-value, после выполнения вызова значение параметра копируется в соответствующее место хранилища, выделенное для данного l-value.

  • Параметры inout являются входными и выходными сразу (in и out). Аргументы, передаваемые как параметры inout должны быть l-value.

  • Отсутствие направления указывает, что параметр соответствует какому-либо из приведенных условий:

    • значение известно в момент компиляции;

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

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

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

  • Если параметр out имеет тип header или header_union, он считается недействительным (invalid).

  • Если параметр out имеет тип стека заголовков, все элементы стека считаются недействительными (invalid), а в поле nextIndex устанавливается 0 (8.17. Операции над стеком заголовков).

  • Если параметр out имеет композитный тип (например, struct), отличающийся от перечисленных выше, правила применяются рекурсивно к элементам композитного типа.

  • Если параметр out имеет иной тип (например, bit<W>), реализация не обязана инициализировать его предсказуемым значением.

Например, если параметр out имеет тип s2_t и имя p

header h1_t {
	bit<8> f1;
	bit<8> f2;
}
struct s1_t {
	h1_t h1a;
	bit<3> a;
	bit<7> b;
}
struct s2_t {
	h1_t h1b;
	s1_t s1;
	bit<5> c;
}

тогда в начале выполнения части программы, имеющей выходной параметр p, он должен инициализироваться с объявлением p.h1b и p.s1.h1a недействительными. Остальные части p инициализировать не требуется. Аргументы оцениваются слева направо до вызова самой функции. Порядок оценки важен, когда представленное для аргумента выражение может давать побочные эффекты. Например,

extern void f(inout bit x, in bit y);
extern bit g(inout bit z);
bit a;
f(a, g(a));

Отметим, что оценка g может изменить аргумент a, поэтому компилятор должен убедиться, что значение, переданное f в качестве первого параметра, не было изменено при оценке второго аргумента. Семантика оценки для вызовов функций задается приведенным ниже алгоритмом (реализация может менять его при условии сохранения результата).

  1. Аргументы оцениваются слева направо в соответствии с выражением при вызове функции.

  2. Если параметр имеет принятое по умолчанию значение и соответствующий аргумент не представлен, в качестве аргумента применяется подразумеваемое значение.

  3. Для каждого аргумента out и inout сохраняется соответствующее значение l-value (это не позволяет изменить его при оценке последующих аргументов). Это важно, если аргумент содержит операции индексирования в стек заголовков.

  4. Значения каждого аргумента сохраняется во временной области.

  5. Функция вызывается с аргументами из временной области. Эти аргументы никогда не являются псевдонимами друг друга, поэтому такой «сгенерированный» вызов функции можно реализовать с помощью ссылки (call-by-reference), если архитектура это позволяет.

  6. При возврате из функции временные значения, соответствующие аргументам out и inout копируются слева направо в l-value, сохраненные в п. 2.

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

bit tmp1 = a;		// оценка a и сохранение результата
bit tmp2 = g(a);	// оценка g(a), сохранение результата, изменение a
f(tmp1, tmp2);	// оценка f, изменение tmp1
a = tmp1;		// копирование результата inout обратно в a

Для подчеркивания важности п. 2 приведенного выше алгоритма рассмотрим пример

header H { bit z; }
H[2] s;
f(s[a].z, g(a));

Оценка этого вызова эквивалента последовательности операторов

bit tmp1 = a;		// сохранение a
bit tmp2 = s[tmp1].z;	// оценка первого аргумента
bit tmp3 = g(a);	// оценка второго аргумента, изменение a
f(tmp2, tmp3);		// оценка f, изменение tmp2
s[tmp1].z = tmp2;	// копирование результата inout обратно, не в s[a].z

При использовании объектов extern в качестве аргументов их можно передавать лишь без направления (см., например, аргументы packet в примере VSS).

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

Основная причина использования семантики copy-in/copy-out (вместо традиционной call-by-reference) заключается в контроле побочных эффектов внешних функций и методов, которые являются основным механизмом взаимодействия программы P4 со своим окружением. Семантика copy-in/copy-out не дает внешним функциям удерживать ссылки на объекты программы P4 и это позволяет компилятору ограничить побочные влияния внешних функций на программу P4 как в пространстве (влияние лишь на параметры out), так и во времени (влияние лишь при вызове функции).

В общем случае внешние функции могут делать все, что угодно — хранить информацию в глобальном хранилище, порождать отдельные потоки, «вступать в сговор» с другими для совместного использования информации, — но они не имеют доступа к переменным программы P4. Семантика copy-in/copy-out позволяет компилятору считать программу P4 вызывающей внешние функции.

Имеется еще два преимущества использования семантики copy-in/copy-out:

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

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

parameterList
	: /* пусто */
	| nonEmptyParameterList
	;

nonEmptyParameterList
	: parameter
	| nonEmptyParameterList ',' parameter
	;

parameter
	: optAnnotations direction typeRef name
	| optAnnotations direction typeRef name '=' expression
	;

direction
	: IN
	| OUT
	| INOUT
	: /* пусто */
	;

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

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

  • Все параметры конструкторов оцениваются во время компиляции, поэтому они не могут иметь направления, это относится к объектам package, control, parser, extern. Значения таких параметров должны быть заданы в момент компиляции и обеспечивать возможность оценки при компиляции (14. Параметризация).

  • Для действий все параметры без направления должны быть в конце списка параметров. Для действий в таблице должны указываться лишь параметры с направлением (13.1. Действия).

  • Действия могут также вызываться явно с использованием синтаксиса функций из блока управления или другого действия. При этом значения всех параметров действия должны быть заданы явно, включая значения параметров без направления, которые в такой ситуации ведут себя как параметры in (13.1.1. Вызов действия).

  • Принятые по умолчанию значение разрешены лишь для параметров без направления и in, они должны преобразовываться в константы, доступные при компиляции.

6.7.2. Необязательные параметры

Параметр, аннотированный как @optional, является необязательным и пользователь может опустить его значение при вызове. Необязательные параметры могут присутствовать лишь в аргументах пакетов, внешних функций и методов, а также конструкторов объектов extern. Такие параметры не могут иметь принятых по умолчанию значений. Если конструкция, подобная процедуре, использует необязательные параметры и подразумеваемые значения, она может вызываться лишь с указанием именованных аргументов. Рекомендуется (но не требуется) размещать необязательные параметры в конце списка параметров.

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

package pipeline(/* параметры опущены */);
package switch(pipeline first, @optional pipeline second);

pipeline(/* аргументы опущены */) ingress;
switch(ingress) main;	// коммутатор с одноэтапным конвейером

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

extern void h(in bit<32> a, in bool b = true);	// принятое по умолчанию значение
// вызовы функций
h(10);		// то же, что и h(10, true);
h(a = 10);	// то же, что и h(10, true);
h(a = 10, b = true);
struct Empty {}
control nothing(inout Empty h, inout Empty m) {
	apply {}
}
parser parserProto<H, M>(packet_in p, out H h, inout M m);
control controlProto<H, M>(inout H h, inout M m);

package pack<HP, MP, HC, MC>(@optional parserProto<HP, MP> _parser, // необязательный параметр
			controlProto<HC, MC> _control = nothing()); // подразумеваемое значение

pack() main;	// Нет значения _parser, а _control является экземпляром nothing()

6.8. Распознавание имен

Объекты P4, создающие пространства имен, организованы в иерархию. Имеется также безымянное пространство верхнего уровня, содержащее все объявления верхнего уровня. Идентификаторы, начинающиеся с точки (.), всегда относятся к пространству имен верхнего уровня.

const bit<32> x = 2;
control c() {
	int<32> x = 0;
	apply {
		x = x + (int<32>).x;	// x - локальная переменная int<32>,
					// .x - переменная bit<32> верхнего уровня
	}
}

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

const bit<4> x = 1;
control p() {
	const bit<8> x = 8;	// объявление x затеняет глобальную переменную x
	const bit<4> y = .x;	// ссылка на x верхнего уровня
	const bit<8> z = x;	// ссылка на локальную (p) переменную x
	apply {}
}

6.9. Видимость

Идентификаторы, определенные на верхнем уровне, видны глобально. Объявления внутри анализатора или элемента управления являются приватными и не могут упоминаться за пределами этого объекта.

7. Типы данных P4

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

7.1. Базовые типы

Ниже перечислены встроенные базовые типы, поддерживаемые P4:

  • void не имеет значения и используется лишь в редких ограниченных обстоятельствах;

  • error служит для передачи сведений об ошибках независимым от платформы, управляемым компилятором способом;

  • string может применяться лишь для строковых констант во время компиляции;

  • match_kind служит для описания реализации поиска в таблицах;

  • bool представляет логические значения;

  • int служит для представления целых чисел произвольного размера;

  • bit<> — битовые строки фиксированного размера;

  • int<> — целые числа фиксированного размера, представленные дополнением до 2;

  • varbit<> — битовые строки с ограничением максимального размера.

baseType
	: BOOL
	| ERROR
	| BIT
	| INT
	| STRING
	| BIT '<' INTEGER '>'
	| INT '<' INTEGER '>'
	| VARBIT '<' INTEGER '>'
	| BIT '<' '(' expression ')' '>'
	| INT '<' '(' expression ')' '>'
	| VARBIT '<' '(' expression ')' '>'
	;

7.1.1. Тип void

Тип указывается ключевым словом void и не содержит значений. Тип не указан в приведенном выше правиле baseType, поскольку его использование в программах P4 существенно ограничено.

7.1.2. Тип error

Тип error содержит значения (opaque), которые могут служить для сигнализации ошибок. Константы типа error определяются в форме

errorDeclaration
	: ERROR '{' identifierList '}'
	;

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

error { ParseError, PacketTooShort }

Базовое представление ошибок зависит от платформы.

7.1.3. Тип match_kind

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

matchKindDeclaration
	: MATCH_KIND '{' identifierList '}'
	;

Основная библиотека P4 содержит приведенное ниже объявление match_kind.

match_kind {
	exact,
	ternary,
	lpm
}

Архитектура может не поддерживать дополнительные типы match_kind. Объявление новых match_kind может выполняться лишь в файлах определения моделей и программисты P4 не могут делать таких объявлений.

7.1.4. Логический тип

Логический тип bool имеет значения false и true, не относящиеся к integer или bit-string.

7.1.5. Строки

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

extern void log(string message);

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

@name("acl") table t1 { /* тело опущено */ }

7.1.6. Целые числа

P4 поддерживает целые числа произвольного размера. Особенности типизации целых чисел приведены ниже.

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

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

  • Правила типизации P4 выбраны так, чтобы поведение было похоже на традиционные программы C.

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

Приоритет арифметических операций идентичен принятому в C.

7.1.6.1. Переносимость

Ни одна платформа P4 не может поддерживать все возможные типы и операции. Например, тип bit<23132312> корректен в P4, но с большой вероятностью не будет поддерживаться на практике всеми платформами. Поэтому каждая платформа вносит ограничения в число поддерживаемых типов. Такие ограничения могут включать:

  • максимальный размер (ширина);

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

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

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

7.1.6.2. Целые числа без знака (bit-string)

Целые числа без знака (bit-string) могут иметь произвольный размер в битах. Строка битов размера W обозначается bit<W>. Значение W должно быть известно (вычисляемо) в момент компиляции (17.1. Известные при компиляции значения) и быть целым числом больше 0. Выражения для размера числа должны указываться в скобках.

const bit<32> x = 10;	// 32-битовая константа со значением 10.
const bit<(x + 2)> y = 15;	// 12-битовая константа со значением 15.
			// при указании размера нужно использовать скобки ()

Биты в bit-string нумеруются от 0 до W-1, бит 0 является младшим, W-1 — старшим. Например, тип bit<128> указывает битовые строки размером 128 битов с номерами битов от 0 до 127, где бит 127 является старшим. Тип bit является сокращением для bit<1>.

Архитектура P4 может вносить дополнительные ограничения для битовых типов, например, может ограничиваться максимальный размер или поддерживаться некоторые арифметические операции лишь для определенных размеров (скажем, 16, 32, 64 бита). Операции, доступные для целых чисел без знака описаны в параграфе 8.5. Операции над битовыми типами (целые числа без знака).

7.1.6.3. Целые числа со знаком

Целые числа со знаком представляются дополнением до 2. Целое число размером W битов объявляется в форме int<W>, где W должно быть выражением, которое в момент компиляции преобразуется в положительное целое число. Биты числа нумеруются от 0 до W-1, бит 0 является младшим, а бит W-1 содержит знак. Например, тип int<64> описывает целые числа, представляемые 64 битами с номерами от 0 до 63, где бит 63 (старший) задает знак.

Архитектура P4 может вносить дополнительные ограничения для чисел со знаком, например, может ограничиваться максимальный размер или поддерживаться некоторые арифметические операции лишь для определенных размеров (скажем, 16, 32, 64 бита). Операции над целыми числами со знаком описаны в параграфе 8.6. Операции над целыми числами фиксированного размера со знаком.

Целое число со знаком размера 1 int<1> может иметь два корректных значения — 0 и -1.

7.1.6.4. Динамические строки битов

В некоторых сетевых протоколах используются поля, размер которых становится известен лишь в процессе работы (например, опции IPv4). Для поддержки ограниченных манипуляций с такими полями в P4 применяется специальный тип битовых строк, размер которых задается в процессе работы — varbit. Тип varbit<W> указывает строку битов размером не более W, где W — положительное целое число, известное при компиляции. Например, тип varbit<120> означает строки битов размером от 0 до 120. Большинство операций, применимых к битовым строкам фиксированного размера (целые числа без знака), не может быть выполнено для динамических битовых строк.

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

7.1.6.5. Целые числа “бесконечной точности”

Тип данных «бесконечной точности» описывает целые числа неограниченного размера — int. Этот тип зарезервирован для целочисленных литералов и выражений, включающих лишь литералы. Ни одно значение P4 не может иметь тип int в процессе работы — компилятор преобразует значения int в подходящие типы фиксированных размеров.

Операции над типом int описаны в параграфе 8.7. Операции над целыми числами произвольной точности. Приведенный ниже пример показывает определения трех констант типа int.

const int a = 5;
const int b = 2 * a;
const int c = b - a + 3;
7.1.6.6. Целочисленные литералы

Типы целочисленных литералов (констант) включают:

  • простые целочисленные константы типа int;

  • положительные целые числа с префиксом размера N и символом w типа bit<N>.

  • целые числа с префиксом размера N и символом s типа int<N>.

В таблице показано несколько примеров целочисленных литералов с их типами. Дополнительные примеры даны в параграфе 6.3.3. Литеральные константы.

Литерал

Интерпретация

10

Тип int, значение 10

8w10

Тип bit<8>, значение 10

8s10

Тип int<8>, значение 10

2s3

Тип int<2>, значение -1 (последние 2 бита), предупреждение о переполнении

1w10

Тип bit<1>, значение 0 (последний бит), предупреждение о переполнении

1s1

Тип int<1>, значение -1, предупреждение о переполнении

7.2. Производные типы

P4 поддерживает множество конструкторов типов, которые можно применять для создания производных типов:

  • enum;

  • header;

  • стек заголовков;

  • struct;

  • header_union;

  • tuple;

  • специализация типа;

  • extern;

  • parser;

  • control;

  • package.

Типы header, header_union, enum, struct, extern, parser, control, package могут использоваться лишь в объявлениях типа, где они задают новое имя типа, которое впоследствии позволяет указывать этот тип.

Другие типы не могут быть объявлены, но синтезируются компилятором для представления типов некоторых языковых конструкций. Эти типы описаны в параграфе 7.2.8. Синтезируемые типы данных (set и function). Например, программист не может объявить переменную типа set, но можно задать выражение, которое будет преобразовываться в этот тип. Эти типы используются в процессе проверки типов.

typeDeclaration
	: derivedTypeDeclaration
	| typedefDeclaration
	| parserTypeDeclaration ';'
	| controlTypeDeclaration ';'
	| packageTypeDeclaration ';'
	;

derivedTypeDeclaration
	: headerTypeDeclaration
	| headerUnionDeclaration
	| structTypeDeclaration
	| enumDeclaration
	;

typeRef
	: baseType
	| typeName
	| specializedType
	| headerStackType
	| tupleType
	;

namedType
	: typeName
	| specializedType
	;

prefixedType
	: TYPE_IDENTIFIER
	| dotPrefix TYPE_IDENTIFIER
	;

typeName
	: prefixedType
	;

7.2.1. Перечисляемые типы

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

enumDeclaration
	: optAnnotations ENUM name '{' identifierList '}'
	| optAnnotations ENUM BIT '<' INTEGER '>' name '{' specifiedIdentifierList '}'
	;

identifierList
	: name
	| identifierList ',' name
	;

specifiedIdentifierList
	: specifiedIdentifier
	| specifiedIdentifierList ',' specifiedIdentifier
	;

specifiedIdentifier
	: name '=' initializer
	;

Например, объявление

enum Suits { Clubs, Diamonds, Hearths, Spades }

вводит новый перечисляемый тип, включающий 4 константы (например, Suits.Clubs). Объявление enum вводит новый идентификатор в текущей области действия для именования созданного типа. Базовое представление перечисляемого типа Suits не задано, поэтому его «размер» в битах не задается (зависит от платформы).

Можно также задать enum с базовым представлением. Иногда это называют сериализацией enum, поскольку в заголовки можно включать поля данного типа enum. Это требует от программиста предоставить целочисленный тип фиксированного размера без знака или со знаком и связанное с ним значение для каждого символьного имени в enum. Например, объявление

enum bit<16> EtherType {
	VLAN	= 0x8100,
	QINQ	= 0x9100,
	MPLS	= 0x8847,
	IPV4	= 0x0800,
	IPV6	= 0x86dd
}

вводит новый перечисляемый тип с 5 константами (например, EtherType.IPV4). Это объявление enum задает представления целым числом фиксированного размера без знака для каждого элемента enum и указывает базовый тип bit<16>. Этот тип объявления enum можно считать объявлением нового типа bit<16>, где переменные или поля этого типа выражаются 16-битовыми целыми числами без знака и отображения символьных имен на числа, заданные enum, по сути определяют константы. Таким способом enum с базовым типом можно представлять как тип, выведенный из базового, что позволяет использовать равенство, присвоение и приведение к базовому типу или из него.

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

enum bit<8> FailingExample {
	first	= 1,
	second	= 2,
	third	= 3,
	unrepresentable = 300
}

будет вызывать ошибку, поскольку значение 300, связанное с FailingExample.unrepresentable выходит за пределы bit<8>.

Выражение для инициализации должно быть известно в момент компиляции. Аннотации, представляемые нетерминальными optAnnotations, описаны в разделе 18. Аннотации, операции со значениями enum — в параграфе 8.3. Операции над типом enum.

7.2.2. Типы заголовков

Для определения типа header применяется показанный ниже синтаксис.

headerTypeDeclaration
	: optAnnotations HEADER name '{' structFieldList '}'
	;

structFieldList
	: /* пусто */
	| structFieldList structField
	;

structField
	: optAnnotations typeRef name ';'
	;

где каждое объявление typeRef ограничено типами bit-string (переменного или фиксированного размера), целыми числами фиксированного размера со знаком, логическим типом или struct (с другими полями struct) с произвольной вложенностью, если все типы «листьев» относятся к bit<W>, int<W>, сериализуемым enum или bool. При использовании bool внутри заголовка P4, все реализации кодируют bool однобитовым полем. Это объявление вводит новый идентификатор в текущей области действия, который можно указывать заданным идентификатором типа. Заголовок похож на структуру C, содержащую все указанные поля. Однако заголовок также включает скрытое логическое поле validity. Когда это поле установлено (true), заголовок считается действительным. При объявлении локальной переменной типа header для бита validity автоматически устанавливается значение false. Менять этот бит можно с использованием методов isValid(), setValid() и setInvalid(), как описано в параграфе 8.16. Операции над заголовками.

Отметим, что вложенные заголовки не поддерживаются. Одна из сложностей состоит в усложнении определения поведения произвольных последовательностей операций setValid, setInvalid и emit. Рассмотрим пример, где заголовок h1 содержит заголовок h2 и оба заголовка действительны (valid). Программа выполняет h2.setInvalid(), за которым следует packet.emit(h1). Следует ли emit выводить все поля h1, пропуская h2? Следует ли h1.setInvalid() объявлять недействительными все заголовки внутри h1 независимо от глубины вложенности?

Заголовок может быть пустым, как показано ниже.

header Empty_h { }

Отметим, что бит validity имеется и в пустом заголовке.

При наличии struct внутри header порядок полей при извлечении и вызове emit совпадает с порядком, указанным в исходном коде. Ниже приведен пример заголовка, включающего struct.

struct ipv6_addr {
	bit<32> Addr0;
	bit<32> Addr1;
	bit<32> Addr2;
	bit<32> Addr3;
}

header ipv6_t {
	bit<4>		version;
	bit<8>		trafficClass;
	bit<20>	flowLabel;
	bit<16>	payloadLen;
	bit<8>		nextHdr;
	bit<8>		hopLimit;
	ipv6_addr 	src;
	ipv6_addr 	dst;
}

Заголовки без полей varbit имеют фиксированный размер, заголовки с полями varbit — переменный. Размер фиксированного заголовка (в битах) не меняется и равен сумме размеров всех его полей (без учета бита validity). Для полей заголовка не используется заполнение или выравнивание. Платформы могут вносить свои ограничения для типа header, например, ограничивать размер целым числом байтов. Ниже приведен пример определения для типичного заголовка Ethernet.

header Ethernet_h {
	bit<48> dstAddr;
	bit<48> srcAddr;
	bit<16> etherType;
}

Приведенное ниже объявление переменной использует определение типа Ethernet_h

Ethernet_h ethernetHeader;

Язык анализа P4 предоставляет точный метод извлечения, который можно применять для «заполнения» полей header из заголовков пакета, как описано в параграфе 12.8. Извлечение данных. При успешном извлечении полей для бита validity устанавливается значение true. Ниже приведен пример заголовка IPv4 с опциями переменного размера.

header IPv4_h {
	bit<4>		version;
	bit<4>		ihl;
	bit<8>		diffserv;
	bit<16>	totalLen;
	bit<16>	identification;
	bit<3>		flags;
	bit<13>	fragOffset;
	bit<8>		ttl;
	bit<8>		protocol;
	bit<16>	hdrChecksum;
	bit<32>	srcAddr;
	bit<32>	dstAddr;
	varbit<320>	options;
}

Как показано в примере параграфа 12.8.2. Извлечение при переменном размере, другим способом поддержки заголовков с полями переменного размера является определение двух заголовков — фиксированного и с полем varbit, поля из которых извлекаются раздельно.

7.2.3. Стеки заголовков

Стек заголовков представляет собой массив заголовков, определяемый как

headerStackType
	: typeName '[' expression ']'
	;

Здесь typeName указывает имя заголовка. Для стека заголовков hs[n] значение n указывает максимальный размер и должно быть положительным целым числом, значение которого известно в момент компиляции. Вложенные стеки заголовков не поддерживаются. Во время работы стек содержит n заголовков типа typeName, из которых действительна лишь часть. Выражения со стеками заголовков рассмотрены в параграфе 8.17. Операции над стеком заголовков.

Например, объявление

header Mpls_h {
	bit<20> label;
	bit<3>	tc;
	bit	bos;
	bit<8>	ttl;
}
Mpls_h[10] mpls;

вводит стек заголовков с именем mpls, содержащий 10 элементов типа Mpls_h.

7.2.4. Объединения заголовков

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

headerUnionDeclaration
	: optAnnotations HEADER_UNION name
		'{' structFieldList '}'
	;

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

Представленный ниже тип Ip_h представляет объединение заголовков IPv4 и IPv6.

header_union IP_h {
	IPv4_h v4;
	IPv6_h v6;
}

Объединение заголовков не рассматривается как тип с фиксированным размером.

7.2.5. Структурные типы

Структурные типы P4 определяются, как показано ниже.

structTypeDeclaration
	: optAnnotations STRUCT name '{' structFieldList '}'
	;

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

header Tcp_h { /* поля опущены */ }
header Udp_h { /* поля опущены */ }
struct Parsed_headers {
	Ethernet_h 	ethernet;
	Ip_h		ip;
	Tcp_h		tcp;
	Udp_h		udp;
}

7.2.6. Кортежи

Кортежи (tuple) похожи на структуры в том, что могут включать много значений. Однако поля кортежей не имеют имен. Тип кортежа с n компонентами типов T1,…,Tn определяется в форме

tuple<T1,/* поля опущены */,Tn>

tupleType
	: TUPLE '<' typeArgumentList '>'
	;

Операторы для работы с tuple описаны в параграфах 8.10. Операции над кортежами и 8.11. Операции над списками.

Тип tuple<> задает кортеж без компонентов.

7.2.7. Правила вложенности типов

В таблице указаны все типы, которые могут служить элементами заголовков, объединений заголовков, структур или кортежей. Отметим, что int указывает целое число «бесконечной» точности, размер которого не задан.

Тип контейнера

Тип элемента

header

header_union

struct или tuple

bit<W>

разрешено

ошибка

разрешено

int<W>

разрешено

ошибка

разрешено

varbit<W>

разрешено

ошибка

разрешено

int

ошибка

ошибка

ошибка

void

ошибка

ошибка

ошибка

error

ошибка

ошибка

разрешено

match_kind

ошибка

ошибка

ошибка

bool

разрешено

ошибка

разрешено

enum

разрешено

ошибка

разрешено

header

ошибка

разрешено

разрешено

header stack

ошибка

ошибка

разрешено

header_union

ошибка

ошибка

разрешено

struct

разрешено

ошибка

разрешено

tuple

ошибка

ошибка

разрешено

Тип int не имеет точных требований к хранилищу в отличие от bit<> и int<>. Значения match_kind бесполезно сохранять в переменной, поскольку они служат лишь для задания сопоставлений полей с ключами поиска в таблице, объявляемых во время компиляции. Тип void бесполезен как часть структуры данных. Заголовки должны иметь точно заданные форматы в виде последовательности битов, чтобы их можно было анализировать и собирать заново.

Отметим, что двухаргументный метод extract (12.8.2. Извлечение при переменном размере) для пакетов поддерживает в заголовке лишь одно поле varbit.

Ниже перечислены все типы, которые могут присутствовать в качестве базовых в typedef или объявлениях типа.

Базовый тип B

typedef B <name>

type B <name>

bit<W>

разрешено

разрешено

int<W>

разрешено

разрешено

varbit<W>

разрешено

ошибка

int

разрешено

ошибка

void

ошибка

ошибка

error

разрешено

ошибка

match_kind

ошибка

ошибка

bool

разрешено

разрешено

enum

разрешено

ошибка

header

разрешено

ошибка

header stack

разрешено

ошибка

header_union

разрешено

ошибка

struct

разрешено

ошибка

tuple

разрешено

ошибка

Имя typedef

разрешено

разрешено

Имя type

разрешено

разрешено

7.2.8. Синтезируемые типы данных

Для проверки типов компилятор P4 может синтезировать представления некоторых типов, которые пользователь не может выразить напрямую. К таким типам относятся set и function.

7.2.8.1. Тип set

Тип set<T> описывает набор значений типа T и может применяться в ограниченном контексте P4. Например, выражение для диапазона 8w5 .. 8w8 описывает набор 8-битовых чисел 5, 6, 7 и 8, т. е. они имеют тип set<bit<8>>;. Это выражение можно использовать как метку в выражении select (12.6. Выражения для выбора), соответствующую любому числу из диапазона. Типы set не могут быть именованными или объявленными программистом P4, они лишь синтезируются компилятором для проверки типов. Выражения типа set описаны в параграфе 8.13. Операции над set.

7.2.8.2. Тип function

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

extern void random(in bit<5> logRange, out bit<32> value);

bit<32> add(in bit<32> left, in bit<32> right) {
	return left + right;
}

Эти определения описывают два объекта:

  • random, который является типом function и представляет:

    • функция имеет результат типа void;

    • функция принимает два параметра;

    • первый параметр имеет направление in, тип bit<5> и имя logRange;

    • второй параметр имеет направление out, тип bit<32> и имя value;

  • add также является типом function и представляет

    • функция имеет результат типа bit<32>;

    • функция принимает два параметра;

    • оба параметра имеют направление in и тип bit<32>.

7.2.9. Внешние типы

P4 поддерживает объявления внешних объектов и внешних функций, как показано ниже.

externDeclaration
	: optAnnotations EXTERN nonTypeName optTypeParameters '{' methodPrototypes '}'
	| optAnnotations EXTERN functionPrototype ';'
	;
7.2.9.1. Внешние функции

Объявление внешней функции задает имя и сигнатуру типа для функции, не задавая ее реализации.

functionPrototype
	: typeOrVoid name optTypeParameters '(' parameterList ')'
	;

Пример объявления внешней функции приведен в параграфе 7.2.8.2. Тип function.

7.2.9.2. Внешние объекты

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

methodPrototypes
	: /* пусто */
	| methodPrototypes methodPrototype
	;

methodPrototype
	: optAnnotations functionPrototype ';'
	| optAnnotations TYPE_IDENTIFIER '(' parameterList ')' ';' // конструктор
	;

typeOrVoid
	: typeRef
	| VOID
	| IDENTIFIER	// может быть переменной типа
	;

optTypeParameters
	: /* пусто */
	| '<' typeParameterList '>'
	;

typeParameterList
	: name
	| typeParameterList ',' name
	;

Например, в основной библиотеке P4 вводятся внешние объекты packet_in и packet_out для операций над пакетами (12.8. Извлечение данных и 15. Сборка пакета). Ниже приведен пример, показывающий вызов этих методов для пакета.

extern packet_out {
	void emit<T>(in T hdr);
}
control d(packet_out b, in Hdr h) {
	apply {
		b.emit(h.ipv4);	// Запись заголовка IPv4 в выходной пакет вызовом emit
}

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

7.2.10. Специализация типа

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

specializedType
	: prefixedType '<' typeArgumentList '>'
	;

В приведенном ниже примере объявление extern описывает базовый блок регистров, где тип сохраняемых в регистре элементов является произвольным T.

extern Register<T> {
	Register(bit<32> size);
	T read(bit<32> index);
	void write(bit<32> index, T value);
}

Тип T должен указываться при создании экземпляра набора регистров путем задания типа Register

Register<bit<32>>(128) registerBank;

Создание экземпляра registerBank выполняется с использованием типа Register заданного привязкой bit<32> к аргументу типа T.

7.2.11. Типы анализаторов и блоков управления

Типы parser и control похожи на тип function и описывают сигнатуру анализатора или блока управления. Такие функции не возвращают значений. Объявления анализаторов и блоков управления в архитектуре могут быть базовыми (т. е. иметь параметры типа).

Типы parser, control и package не могут служить типами аргументов для методов, анализаторов, элементов управления, таблиц или действий. Они могут служить типами для аргументов, передаваемых конструкторам (14. Параметризация).

7.2.11.1. Объявление типа анализатора

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

parserTypeDeclaration
	: optAnnotations PARSER name optTypeParameters
	'(' parameterList ')'
	;

Например, ниже показано объявление типа parser с именем P, параметризованное переменной типа H. Анализатор, получивший на входе packet_in со значением b, создает на выходе два значения:

  • заданного пользователем типа H;

  • предопределенного типа Counters.

struct Counters { /* поля опущены */ }
parser P<H>(packet_in b,
	out H packetHeaders,
	out Counters counters);
7.2.11.2. Объявление типа блока управления

Объявление типа элемента управления (control) описывает сигнатуру блока управления и похоже на объявление типа parser.

controlTypeDeclaration
	: optAnnotations CONTROL name optTypeParameters
	'(' parameterList ')'
	;

7.2.12. Типы пакетов (package)

Тип package описывает сигнатуру программного пакета.

packageTypeDeclaration
	: optAnnotations PACKAGE name optTypeParameters
	'(' parameterList ')'
;

Все параметры package оцениваются при компиляции и не должны указывать направления (не могут быть in, out, inout). В остальном типы package похожи на parser. Для пакетов могут лишь создаваться экземпляры без управления поведением при работе.

7.2.13. Типы, не имеющие значения (don’t care)

Не имеющие значения типы (_) могут применяться в некоторых обстоятельствах. Их следует использовать лишь там, где возможна запись переменной привязанного типа. Символ подчеркивания может применяться для снижения сложности кода, когда не имеет значения конкретная привязка переменной (например при унификации типа don’t care может комбинироваться с любым другим типом). Пример рассмотрен в параграфе 16.1. Пример описания архитектуры.

7.3. Подразумеваемые значения

Для некоторых типов P4 определены «принятые по умолчанию значения», которые могут автоматически применяться при инициализации данного типа.

  • Для int, bit<N> и int<N> подразумевается 0.
  • Для bool подразумевается false.
  • Для error подразумевается error.NoError (определено в core.p4).
  • Для string подразумевается пустая строка «».

  • Для varbit<N> подразумевается строка нулей (в P4 сейчас нет литерала для этого).

  • Для enum с базовым типом подразумевается 0, даже если 0 реально не зазван среди значений enum.

  • Для enum без базового типа подразумевается первое значение, появляющееся в объявлении типа enum.

  • Для header подразумевается invalid.
  • Для стека заголовков подразумевается, что все элементы являются invalid, а nextIndex = 0.
  • Для header_union подразумевается invalid во всех элементах.
  • Для struct подразумевается структура, где каждое поле имеет принятое по умолчанию значение в соответствии с типом поля, если такое значение определено.
  • Для a tuple подразумевается кортеж, где каждое поле имеет принятое по умолчанию значение в соответствии с типом поля, если такое значение определено.

Отметим, что некоторые типы не имеют подразумеваемых значений, например, это match_kind, set, function, extern, parser, control, package.

7.4. typedef

Объявление typedef можно использовать для создания дополнительного имени типа.

typedefDeclaration
	: optAnnotations TYPEDEF typeRef name ';'
	| optAnnotations TYPEDEF derivedTypeDeclaration name ';'
	;

typedef bit<32> u32;
typedef struct Point { int<32> x; int<32> y; } Pt;
typedef Empty_h[32] HeaderStack;

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

7.5. Создание новых типов

Подобно typedef, можно использовать ключевое слово type для определения новых типов.

	| optAnnotations TYPE typeRef name
	| optAnnotations TYPE derivedTypeDeclaration name

type bit<32> U32;
U32 x = (U32)0;

В отличие от typedef, ключевое слово type создает новый тип, не являющийся синонимом существующего. Значения исходного и вновь созданного типа нельзя смешивать в выражениях.

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

type bit<9> PortId_t;

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

8. Выражения

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

Правило грамматики для выражений общего назначение имеет вид

expression
	: INTEGER
	| TRUE
	| FALSE
	| STRING_LITERAL
	| nonTypeName
	| dotPrefix nonTypeName
	| expression '[' expression ']'
	| expression '[' expression ':' expression ']'
	| '{' expressionList '}'
	| '{' kvList '}'
	| '(' expression ')'
	| '!' expression
	| '~' expression
	| '-' expression
	| '+' expression
	| typeName '.' member
	| ERROR '.' member
	| expression '.' member
	| expression '*' expression
	| expression '/' expression
	| expression '%' expression
	| expression '+' expression
	| expression '-' expression
	| expression SHL expression	// SHL - это сдвиг влево (<<)
	| expression '>''>' expression	// символы >> не должны быть разделены
	| expression LE expression		// LE - это меньше или равно (<=)
	| expression GE expression
	| expression '<' expression
	| expression '>' expression
	| expression NE expression		// NE - не равно (!=)
	| expression EQ expression		// EQ - равно (==)
	| expression '&' expression
	| expression '^' expression
	| expression '|' expression
	| expression PP expression		// PP это ++
	| expression AND expression	// AND это &&
	| expression OR expression		// OR это ||
	| expression '?' expression ':' expression
	| expression '<' realTypeArgumentList '>' '(' argumentList ')'
	| expression '(' argumentList ')'
	| namedType '(' argumentList ')'
	| '(' typeRef ')' expression
	;
expressionList
	: /* пусто */
	| expression
	| expressionList ',' expression
	;
member
	: name
	;
argumentList
	: /* пусто */
	| nonEmptyArgList
	;
nonEmptyArgList
	: argument
	| nonEmptyArgList ',' argument
	;
argument
	: expression
	;
typeArg
	: DONTCARE
	| typeRef
	| nonTypeName
	;
typeArgumentList
	: /* пусто */
	| typeArg
	| typeArgumentList ',' typeArg
	;

Полная грамматика P4 приведена в Приложении H.

Приведенная грамматика не показывает очередности операций. Порядок действий похож на применяемый в C с одним исключением и некоторыми дополнениями. Приоритет побитовых операций &, | и ^ выше приоритета <, <=, >, >=. Это более естественно с учетом добавления логического типа true в систему типов, поскольку побитовые операции не могут применяться к логическим типам. Конкатенация (++) имеет такой же приоритет, что и инфиксное сложение. «Нарезка» битов a[m:l] имеет такой же приоритет как индексирование массива (a[i]).

В дополнение к этому P4 поддерживает выражения выбора (select, 12.6. Выражения для выбора), которые могут применяться лишь в анализаторах.

8.1. Порядок операций

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

  • Логические операторы && и || оцениваются в сокращенном порядке, т. е. второй операнд учитывается лишь при необходимости.

  • В условных операторах e1 ? e2 : e3 оценивается e1, затем e2 или e3.

  • Все остальные выражения вычисляются слева направо в соответствии с порядком в коде программы.

  • Вызовы методов и функций оцениваются в соответствии с параграфом 6.7. Соглашения о вызовах.

8.2. Операции над типом error

Символические имена, заданные определениями ошибок, относятся к пространству имен ошибок. Для типа error поддерживаются лишь операции сравнения «равно» (==) и «не равно» (!=), результатом которых является логическое значение. Например, приведенная ниже строка проверяет наличие определенной ошибки

error errorFromParser;

if (errorFromParser != error.NoError) { /* код опущен */ }

8.3. Операции над типом enum

Символические имена, заданные определениями перечисляемых типов, относятся к пространствам имен, созданным объявлениями enum, а не к пространству верхнего уровня.

enum X { v1, v2, v3 }
X.v1	// ссылка на v1
v1	// ошибка - v1 не относится к пространству имен верхнего уровня

Подобно error, выражения enum без указания базового типа поддерживают лишь операции сравнения равенства (==) и неравенства (!=). Выражения type без указания базового типа нельзя привести к иному типу (или из иного типа).

Для enum можно указать базовый тип, как показано ниже.

enum bit<8> E {
	e1 = 0,
	e2 = 1,
	e3 = 2
}

Можно отобразить несколько символьных значений enum на одно целое число с фиксированным значением.

enum bit<8> NonUnique {
	b1 = 0,
	b2 = 1,	// b2 и b3 имеют одинаковые значения.
	b3 = 1,
	b4 = 2
}

Для enum с базовым типом поддерживается приведение базового типа, например

bit<8> x;
E a = E.e2;
E b;

x = (bit<8>) a; 	// устанавливает x = 1
b = (E) x;		// устанавливает b = E.e2

Значение a, которое было инициализировано как E.e2 приводится к типу bit<8> с использованием заданного представления целого числа без знака с фиксированным размером для E.e2 и значением 1. Затем для переменной b устанавливается символьное значение E.e2, которое соответствует целому числу без знака с фиксированным размером и значением 1.

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

bit<8> x = E.e2; // устанавливает x = 1 (E.e2 автоматически приводится к bit<8>)

E a = E.e2
bit<8> y = a << 3; // устанавливает y = 8 (автоматически приводится к bit<8> и сдвигается)

Неявное приведение базового типа с фиксированным размером к enum не поддерживается.

enum bit<8> E1 {
	e1 = 0, e2 = 1, e3 = 2
}

enum bit<8> E2 {
	e1 = 10, e2 = 11, e3 = 12
}
E1 a = E1.e1;
E2 b = E2.e2;

a = b;	// Ошибка - b автоматически приводится к bit<8>,
	// но bit<8> не приводится автоматически к E1

a = (E1) b; // Корректно
a = E1.e1 + 1; 	// Ошибка - E.e1 автоматически приводится к bit<8>
			// и правая часть выражения имеет тип bit<8>, 
			// который нельзя автоматически привести к E.

a = (E1)(E1.e1 + 1); // Явное приведение типа делает назначение корректным

a = E1.e1 + E1.e2; 	// Ошибка - оба аргумента сложения автоматически
			// приводятся к bit<8>. Сложение корректно, 
			// но присваивание недействительно.

a = (E1)(E2.e1 + E2.e2); // Явное приведение делает присваивание корректным.

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

E1	a = E1.e1;
E2	b = E2.e2;
bit<8> c;

if (a > b) { // Возможно предупреждение о двух автоматический и разных приведениях к bit<8>.
		// Код опущен
}

c = a + b; // Корректно, но разумно предупредить.

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

bit<8> x = 5;
E e = (E) x; // Устанавливает для e значение без имени.

Для e устанавливается неименованное значение, поскольку отсутствует символ, соответствующий целому числу без знака с фиксированным размером и значением 5. Например, в приведенном ниже фрагменте кода может быть достигнута ветвь else в блоке if/else if/else, даже когда сопоставление с x выполнено относительно символов, определенных в MyPartialEnum_t.

enum bit<2> MyPartialEnum_t {
	VALUE_A = 2w0,
	VALUE_B = 2w1,
	VALUE_C = 2w2
}

bit<2> y = < некое значение >;
MyPartialEnum_t x = (MyPartialEnum_t)y;

if (x == MyPartialEnum_t.VALUE_A) {
	// Тот или иной код
} else if (x == MyPartialEnum_t.VALUE_B) {
	// Тот или иной код
} else if (x == MyPartialEnum_t.VALUE_C) {
	// Тот или иной код
} else {	// Компилятор P4 должен предполагать, что эта ветвь может быть выполнена
	// Тот или иной код
}

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

enum bit<16> EtherType {
	VLAN	= 0x8100,
	IPV4	= 0x0800,
	IPV6	= 0x86dd
}

header ethernet {
	// Часть полей опущена
	EtherType etherType;
}

parser my_parser(/* параметры опущены */) {
	state parse_ethernet {
		packet.extract(hdr.ethernet);
		transition select(hdr.ethernet.etherType) {
			EtherType.VLAN : parse_vlan;
			EtherType.IPV4 : parse_ipv4;
			EtherType.IPV6: parse_ipv6;
			default: reject;
		}
	}
}

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

  • В выражениях select следует соответствовать варианту default или _ в выражении набора ключей.

  • В качестве ключа с троичным match_kind в таблице следует соответствовать записи, где для всех битов поля установлено don’t care.

  • В качестве ключа с match_kind lpm следует соответствовать записи, где это поле имеет префикс размера 0.

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

8.4. Логические выражения

Для логических выражений поддерживаются операции И (&&), ИЛИ (||), НЕ (!), равно (==) и не равно (!=). Порядок выполнения операций аналогичен принятому в C и использует сокращение (при очевидном результате расчет прекращается). P4 не использует неявного приведения логических значений к bit-string и обратно. В результате обычные для C выражения вида

if (x) /* тело опущено */

(x — целочисленный тип) должно записываться в P4 как

if (x != 0) /* тело опущено */

В параграфе 8.9.2. Неявное приведение описана оценка 0 в этом выражении.

8.4.1. Условный оператор

Условные выражения вида e1 ? e2 : e3 ведут себя как в языке C. Как было отмечено выше, сначала оценивается выражение e1, затем e2 или e3 в зависимости от первого результата. Первое субвыражение должно иметь логический тип, а второе и третье должны быть однотипными, но не могут быть целочисленными с бесконечной разрядностью, если само условие не может быть оценено в момент компиляции. Это ограничение предназначено для того, чтобы размер результата условного выражения можно было статически вывести во время компиляции.

8.5. Операции над битовыми типами (целые числа без знака)

В этом разделе рассматриваются все операции, которые могут быть выполнены над выражениями типа bit<W> для заданного W (их называют также битовыми строками).

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

Архитектура платформ P4 может поддерживать арифметику с насыщением. Все операции с насыщением ограничены фиксированным диапазоном от минимального до максимального значения. Арифметика с насыщением имеет преимущества, особенно при использовании в счетчиках. Результат достижения максимума в счетчике с насыщением значительно ближе к реальному результату, нежели переполнение счетчика и начало отсчета с 0. Согласно Wikipedia, арифметика с насыщением численно близка к верному ответу, насколько это возможно. Для 8-битовой двоичной арифметики со знаком в случае корректного ответа 130 гораздо менее удивляет получение ответа 127 в арифметике с насыщением, нежели −126 от модульной арифметики. Аналогично для 8-битовой двоичной арифметики без знака при корректном ответе 258 меньшим сюрпризом будет получение ответ 255 от арифметики с насыщением, нежели 2 от модульной арифметики. В настоящее время P4 определяет операции с насыщением лишь для сложения и вычитания. Для целых чисел без знака размером W минимальным значением является 0, а максимальным 2W-1. Приоритет операций сложения и вычитания с насыщением совпадает с приоритетом тех же операций в модульной арифметике.

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

  • Проверка равенства битовых строк одного размера обозначается == и дает логический результат.

  • Проверка неравенства битовых строк одного размера обозначается != и дает логический результат.

  • Сравнение беззнаковых чисел одного размера — <, >, <=, >= дает логический результат.

Перечисленные ниже операции возвращают результат bit-string при работе с битовыми строками одного размера.

  • Отрицание или смена знака (-) выполняется вычитанием значения из 2W. Результатом служит целое число без знака с тем же размером. Семантика совпадает с принятой в C для целых чисел без знака.

  • Унарный плюс (+) реально не делает ничего.

  • Сложение (+) является ассоциативной операцией. Результат получается путем отсечки3 полученной суммы до нужного размера (как в C).

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

  • Умножение (*). Результат получается путем отсечки произведения до нужного размера. Архитектура P4 может вносить дополнительные ограничения, например, разрешать умножение лишь на степени 2.

  • Побитовая операция И между двумя операндами одного размера (&).

  • Побитовая операция ИЛИ между двумя операндами одного размера (|).

  • Побитовое дополнение одной битовой строки (~).

  • Побитовая операция Исключительное-ИЛИ (XOR) между двумя операндами одного размера (^).

  • Сложение с насыщением (|+|).
  • Вычитание с насыщением (|-|).

Для битовых строк поддерживаются также описанные ниже операции.

  • Извлечение непрерывного набора битов, называемое «нарезкой» (slice), обозначается [m:l], где m и l должны быть положительными целыми числами, известными при компиляции и m >= l. Результатом является строка битов размером m — l + 1, включая биты от l (младший бит результата) до m (старший) исходного операнда. Выполнение условий 0 <= l < W и l <= m < W проверяется статически (W — размер исходной строки битов). Отметим, что обе конечные точки извлечения включаются в результат. Границы нужны в момент компиляции, чтобы можно было рассчитать размер результата. Нарезки относятся к l-value, поэтому P4 поддерживает для них присваивание e[m:l] = x . В этом случае устанавливаются биты от m до l строки e в соответствии с битами x, а остальные биты не меняются. «Нарезка» числа без знака является числом без знака.

  • Логический сдвиг влево или вправо на известное в процессе работы целое число без знака обозначается << и >>. При сдвиге влево левый операнд является беззнаковым, а правый должен быть выражением типа bit<S> или неотрицательным целочисленным литералом. Результат имеет тот же тип, что был у левого операнда. Сдвиг на величину, превышающую размер, обнуляет все биты.

8.6. Операции над целыми числами фиксированного размера со знаком

В этом разделе рассмотрены все операции, которые могут быть выполнены над выражениями типа int<W> для данного W. Напомним, что int<W> обозначает целые числа со знаком W-bit, представленные дополнением до 2.

В общем случае арифметические операции P4 не детектируют переполнения или исчерпания — операции просто «начинают отсчет с 0 (wrap around), как в операциях C с целыми числами без знака. Поэтому попытка представить большое число размером W будет сохранять лишь младшие W битов значения.

P4 поддерживает арифметику с насыщением (сложение и вычитание) для целых чисел со знаком. Платформы могут отвергать арифметические операции с насыщением. Для целого числа со знаком размера W минимальным значением является -2(W-1), а максимальным 2(W-1)-1.

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

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

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

Ниже перечислены операции, поддерживаемые для данных типа int<W>. Эти операции требуют однотипных операндов, а результат всегда имеет размер левого операнда.

  • Отрицание или смена знака (-).

  • Унарный плюс (+) реально не делает ничего.

  • Сложение (+).

  • Вычитание (-).

  • Сравнение на равенство (==) и неравенство (!=), дающее логический результат.

  • Численные сравнения <, <=, >, и >=, дающие логический результат.

  • Умножение (*). Размер результата совпадает с размером операндов. Архитектура P4 может вносить дополнительные ограничения, например, умножение лишь на степени 2.

  • Сложение с насыщением (|+|).
  • Вычитание с насыщением (|-|).

  • Арифметический сдвиг влево (<<) и вправо (>>). Левый операнд имеет знак, а правый должен быть беззнаковым типа bit<S> или неотрицательным целочисленным литералом. Результат всегда имеет тип левого операнда. Сдвиг влево ведет себя точно так же, как для чисел без знака. Сдвиг на число, превышающее размер, ведет к корректному результату:

    • все нули при сдвиге влево;

    • все нули при сдвиге вправо на положительное значение;

    • все 1 при сдвиге вправо на положительное значение.

  • Извлечение непрерывного набора битов, называемое «нарезкой» (slice), обозначается [m:l], где m и l должны быть положительными целыми числами, известными при компиляции и m >= l. Результатом является целое число без знака размером m — l + 1, включая биты от l (младший бит результата) до m (старший) исходного операнда. Выполнение условий 0 <= l < W и l <= m < W проверяется статически (W — размер исходной строки битов). Отметим, что обе конечные точки извлечения включаются в результат. Границы нужны в момент компиляции, чтобы можно было рассчитать размер результата. Нарезки относятся к l-value, поэтому P4 поддерживает для них присваивание e[m:l] = x . В этом случае устанавливаются биты от m до l строки e в соответствии с битами x, а остальные биты не меняются. «Нарезка» числа без знака является числом без знака.

8.6.1. Конкатенация

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

8.6.2. Замечания о сдвиге

Сдвиги (со знаком или без знака) имеют ряд рассмотренных ниже особенностей.

  • Сдвиг вправо отличается при для чисел со знаком и без него, сдвиг числа со знаком является арифметическим.

  • Сдвиг на отрицательное значение не имеет явной семантики и система типизации P4 считает его некорректным.

  • В отличие от C сдвиг на величину, превышающую размер дает четко определенный результат.

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

Рассмотрим несколько примеров.

bit<8> x;
bit<16> y;
bit<16> z = y << x;
bit<16> w = y << 1024;

Как отмечено выше, P4 дает строго определенный результат при сдвиге, превышающем размер (в отличие от C).

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

8.7. Операции над целыми числами произвольной точности

Тип int обозначает целые числа произвольной точности (разрядности). Для всех выражений типа int значения должны быть известны в момент компиляции. Поддерживаемые для типа int операции P4 перечислены ниже.

  • Отрицание или смена знака (-).

  • Унарный плюс (+) реально не делает ничего.

  • Сложение (+).

  • Вычитание (-).

  • Сравнение на равенство (==) и неравенство (!=), дающее логический результат.

  • Численные сравнения <, <=, >, и >=, дающие логический результат.

  • Умножение (*).

  • Деление одного положительного значения на другое с отсечкой (/).

  • Деление одного положительного значения на другое по модулю (%).

  • Арифметический сдвиг влево (<<) и вправо (>>). Результат сдвига имеет тип int. Правый операнд должен быть положительной константой. Выражение a << b эквивалентно a × 2b, а a >> b — ⌊a/2b ⌋.

Все операнды приведенных выше действий должны иметь тип int. В двоичных операция не допускается комбинация значений типа int и значений типов с фиксированным размером. Однако в некоторых случаях компилятор автоматически выполняет приведение int к типам с фиксированным размером (8.9. Приведение типов).

Все расчеты со значениями int выполняются без потери информации. Например, перемножение двух 1024-битовых значений может дать результат размером 2048 битов (отметим, что конкретное представление значений int не задано). Значения int можно привести к типу bit<w> и int<w>. Приведение int к значению с фиксированные размером будет сохранять соответствующее число младших битов. При потере старших битов компилятору следует выдавать предупреждение.

Отметим, что побитовые операции (|, &, ^, ~) не определены для типа int. Кроме того, не допускаются операции деления (в том числе по модулю) на отрицательное число. Арифметика с насыщением не поддерживается для целых чисел с производной разрядностью.

8.8. Операции над битовыми строками переменного размера

Для поддержки анализа заголовков с полями переменного размера в P4 служит тип varbit. При каждом объявлении этого типа статически задается максимальный размер. До инициализации динамический размер битовой строки остается неизвестным. Для таких строк поддерживается ограниченный набор операций.

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

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

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

  • Анализатор извлекает данные в заголовок переменного размера с использованием двухаргументного метода extract во внешнем объекте packet_in (12.8.2. Извлечение при переменном размере), устанавливая динамический размер объекта.

  • Метод emit внешнего объекта packet_out может выполняться для заголовков и некоторых других типов (15. Сборка пакета), содержащих поля varbit. Вызов emit вставляет битовую строку переменного размера с известным динамическим размером в создаваемый пакет.

8.9. Приведение типов

P4 поддерживает ограниченное приведение типов, записываемое в форме (t) e, где t указывает тип, а e — выражение. Приведение возможно лишь для базовых типов. Это может показаться неудобным для программистов, но обеспечивает ряд преимуществ:

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

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

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

8.9.1. Явное приведение

Ниже перечислены корректные приведения типов в P4:

  • bit<1> <-> bool преобразует 0 в false, 1 — в true и обратно;

  • int<W> -> bit<W> сохраняет все биты неизменными, переводя отрицательные числа в положительные;

  • bit<W> -> int<W> сохраняет все биты неизменными, переводя числа со старшим битом 1 в отрицательные;

  • bit<W> -> bit<X> отсекает значение при W > X и дополняет нулями при W <= X.

  • int<W> -> int<X> отсекает значение при W > X и добавляет бит знака при W < X.

  • int -> bit<W> преобразует целое число в достаточно большое дополнение до 2 для предотвращения потери информации, после чего отсекает результат до размера W; компилятору следует выдавать предупреждение о переполнении или преобразовании в отрицательное число;

  • int -> int<W> преобразует целое число в достаточно большое дополнение до 2 для предотвращения потери информации, после чего отсекает результат до размера W; компилятору следует выдавать предупреждение о переполнении;

  • приведение между парой типов, заданных typedef, эквивалентное одной из приведенных выше комбинаций;

  • приведение между типом, заданным type, и исходным типом;

  • приведение между enum с явным типом и исходным типом.

8.9.2. Неявное приведение

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

enum bit<8> E {
	a = 5;
}
bit<8>		x;
bit<16>	y;
int<8>		z;

компилятор добавит неявные приведения, показанные ниже.

  • x + 1 станет x + (bit<8>)1;
  • z < 0 станет z < (int<8>)0;
  • x << 13 станет 0 с выдачей предупреждения о переполнении;
  • x | 0xFFF станет x | (bit<8>)0xFFF с выдачей предупреждения о переполнении;
  • x + E.a станет x + (bit<8>)E.a.

8.9.3. Недействительные арифметические выражения

Многие из арифметических выражений, доступных в других языках, не разрешены в P4. Для иллюстрации рассмотрим пример.

bit<8>		x;
bit<16>	y;
int<8>		z;

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

Выражение

Причина непригодности

Альтернативы

x + y

Разные размеры

(bit<16>)x + y
x + (bit<8>)y

x + z

Разные знаки

(int<8>)x + z
x + (bit<8>)z

(int<8>)y

Невозможно изменить сразу знак и размер

(int<8>)(bit<8>)y
(int<8>)(int<16>)y

y + z

Разные знаки и размеры

(int<8>)(bit<8>)y + z
y + (bit<16>)(bit<8>)z
(bit<8>)y + (bit<8>)z
(int<16>)y + (int<16>)z

x << z

Левый операнд сдвига не может иметь знака

x << (bit<8>)z

x < z

Разные знаки

X < (bit<8>)z
(int<8>)x < z

1 << x

Размер значения 1 неведом

32w1 << x

~1

Побитовая операция над int

~32w1

5 & -3

Побитовая операция над int

32w5 & -3

8.10. Операции над кортежами

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

tuple<bit<32>, bool> x = { 10, false };

8.11. Операции над списками

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

expression ...
	| '{' expressionList '}'
expressionList
	: /* пусто */
	| expression
	| expressionList ',' expression
	;

Типом выражения со списком является tuple (7.2.8. Синтезируемые типы данных). Выражения со списками могут присваиваться типам tuple, struct или header, а также передаваться методам в качестве аргументов, однако выражения со списками не являются l-value. Списки могут быть вложенными. Например, приведенный ниже фрагмент кода использует выражение со списком для одновременной передачи нескольких полей заголовка системе обучения.

extern LearningProvider {
	void learn<T>(in T data);
}
LearningProvider() lp;

lp.learn( { hdr.ethernet.srcAddr, hdr.ipv4.src } );

Список можно применять для инициализации структуры, если число элементов списка совпадает с числом полей структуры. Результатом такой инициализации будет присвоение i-го элемента списка i-му полю структуры.

struct S {
	bit<32> a;
	bit<32> b;
}
const S x = { 10, 20 }; // a = 10, b = 20

Выражения со списками можно также применять для инициализации переменных с типом tuple.

tuple<bit<32>, bool> x = { 10, false };

Пустой список имеет тип tuple<> — кортеж без элементов.

8.12. Выражения со значением struct

Можно написать выражение, оценка (расчет) которого дает тип struct или header. Синтаксис выражения имеет вид

expression ...
	| '{' kvList '}'
	| '(' typeRef ')' expression
	;
kvList
	: kvPair
	| kvList "," kvPair
	;
kvPair
	: name "=" expression
	;

Для такого выражения typeRef задает имя типа структуры или заголовка и может быть опущено, если его можно вывести из контекста, например, при инициализации переменной с типом struct. Ниже приведен пример использования выражения в проверке равенства.

struct S {
	bit<32> a;
	bit<32> b;
}
S s;
// Сравнение с выражением типа struct
bool b = s == (S) { a = 1, b = 2 };

Выражения struct можно использовать в правой части операций присваивания, в сравнениях, выражениях полей выбора, а также в качестве аргументов функций, методов или действий. Эти выражения не могут быть l-value.

8.13. Операции над set

Некоторые выражения P4 обозначают наборы значений (set<T> для некого T, 7.2.8.1. Тип set). Эти выражения могут появляться лишь в ограниченном контексте — анализаторах и постоянных записях таблиц. Например, выражение select (12.6. Выражения для выбора) может иметь показанную ниже структуру.

select (expression) {
	set1: state1;
	set2: state2;
	// Остальные метки опущены
}

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

keysetExpression
	: tupleKeysetExpression
	| simpleKeysetExpression
	;

tupleKeysetExpression
	: '(' simpleKeysetExpression ',' simpleExpressionList ')'
	;

simpleExpressionList
	: simpleKeysetExpression
	| simpleExpressionList ',' simpleKeysetExpression
	;

simpleKeysetExpression
	: expression
	| DEFAULT
	| DONTCARE
	| expression MASK expression
	| expression RANGE expression
	;

Операторы mask (&&&) и range (..) имеют одинаковый приоритет, который выше приоритета &.

8.13.1. Одноэлементные наборы

В контексте set (набор, множество) выражения обозначают одноэлементные наборы. Например, во фрагменте

select (hdr.ipv4.version) {
	4: continue;
}

метка 4 обозначает набор с единственным элементом 4.

8.13.2. Универсальный набор

В контексте set выражение default или _ обозначает универсальный набор, содержащий все возможные значения данного типа

select (hdr.ipv4.version) {
	4: continue;
	_: reject;
}

8.13.3. Маски

Инфиксный оператор &&& принимает два аргумента типа bit<W> или сериализованных enum и создает значение типа set<ltype>, где ltype является типом левого аргумента. Значение справа служит маской, где каждый бит 0 указывает, что соответствующий бит не имеет значения (don’t care). Более формально, набор, обозначенный a &&& b, определяется как

a &&& b = { c of type bit<W>, где a & b = c & b }

Например,

8w0x0A &&& 8w0x0F

Обозначает набор из 16 разных 8-битовых значений с битовой маской XXXX1010, где X может принимать любое значение. Отметим, что может быть много способов указать набор ключей с использованием оператора маскирования, например, 8w0xFA &&& 8w0x0F даст такой же набор, что и приведенное выше выражение.

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

8.13.4. Диапазоны

Инфиксный оператор .. принимает два аргумента одного типа T, в качестве которого может служить bit<W> или int<W> и создает значение типа set<T>. Множество содержит все значения от левого до правого операнда включительно. Например,

4w5 .. 4w8

обозначает 4w5, 4w6, 4w7, 4w8.

8.13.5. Произведение множеств

Можно комбинировать множества (set) с помощью декартова произведения

select(hdr.ipv4.ihl, hdr.ipv4.protocol) {
	(4w0x5, 8w0x1): parse_icmp;
	(4w0x5, 8w0x6): parse_tcp;
	(4w0x5, 8w0x11): parse_udp;
	(_, _): accept; }

Типом произведения множеств является множество кортежей.

8.14. Операции над типом struct

Единственной операцией для выражения типа struct является доступ к полям на основе нотации с точкой (.), например, s.field. Если s является l-value, то s.field также будет l-value. P4 позволяет копировать структуры с использованием операторов присваивания, когда источник и назначение одинаковы по структуре. Кроме того, структуру можно инициализировать выражением списка, как описано в параграфе 8.11. Операции над списками, или инициализатором структуры, как описано в следующем параграфе. В обоих случаях должны инициализироваться все поля структуры.

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

8.15. Инициализаторы структур

Структуры можно инициализировать с помощью выражений, значениями которых является структура (8.12. Выражения со значением struct), как показано ниже.

struct S {
	bit<32> a;
	bit<32> b;
}
const S x = { a = 32, b = 20 };
const S x = (S){ a = 32, b = 20 }; // эквивалент

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

8.16. Операции над заголовками

Для заголовков поддерживаются те же операции, что и для структур. Присвоение значения заголовку копирует также бит validity. Кроме того, для заголовков поддерживаются указанные ниже методы.

  • isValid() возвращает значение бита validity в заголовке;

  • setValid() устанавливает для бита validity значение true (применимо лишь к l-value);

  • setInvalid() устанавливает для бита validity значение false (применимо лишь к l-value).

Выражение h.minSizeInBits() определено для любого h с типом header. Значением выражения является сумма размеров всех полей h, при этом поля varbit учитываются с размером 0. Выражение h.minSizeInBits() является константой в момент компиляции и имеет тип int. Выражение h.minSizeInBytes() похоже на h.minSizeInBits(), но возвращает общий размер полей заголовка в байтах с округлением в большую сторону, если размер заголовка не содержит целого числа байтов. h.minSizeInBytes() = (h.minSizeInBits() + 7) >> 3.

Подобно структурам, объект header можно инициализировать выражением со списком (8.11. Операции над списками), где содержатся все поля заголовка в нужном порядке или инициализатором структуры (8.14. Операции над типом struct). Инициализированный заголовок автоматически становится действительным.

header H { bit<32> x; bit<32> y; }
H h;
h = { 10, 12 };		// Это также делает заголовок h действительным
h = { y = 12, x = 10 };	// то же самое

Два однотипных заголовка можно сравнить на равенство (==) или неравенство (!=). Заголовки считаются равными при совпадении значений всех полей, включая validity. В параграфе 8.22. Чтение неинициализированных значений и запись в недействительные заголовки описано поведение в случаях считывания полей неинициализированного заголовка или записи в заголовок, который не является действительным.

8.17. Операции над стеком заголовков

Стек заголовков является массивом фиксированного размера с однотипными заголовками. Действительные элементы стека заголовков не обязаны быть непрерывными. P4 поддерживает набор операций для стеков заголовков. Стек заголовков hs типа h[n] можно описать приведенным ниже псевдокодом.

// объявление типа
bit hs_t {
	bit<32> 	nextIndex;
	bit<32> 	size;
	h[n] 		data;	// обычный массив
}

// Объявление и создание экземпляра
hs_t hs;
hs.nextIndex = 0;
hs.size = n;

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

Для стека заголовков hs размером n приведенные ниже выражения будут действительны.

  • hs[index] указывает заголовок в конкретной позиции внутри стека. Если hs является l-value, результат также будет l-value. Заголовок может быть недействительным. Некоторые реализации могут требовать, чтобы выражение index было известно при компиляции. Компилятор P4 должен выдавать ошибку, если значение индекса при компиляции выходит за рамки. Доступ к стеку заголовков hs по индексу меньше 0 или больше hs.size возвращает неопределенное значение (8.22. Чтение неинициализированных значений и запись в недействительные заголовки).

  • hs.size — возвращает 32-битовое целое число без знака, указывающее размер стека заголовков (константа в момент компиляции).

  • Присваивание из стека заголовков hs в другой стек требует, чтобы оба стека имели один тип и размер. Копируются все компоненты hs, включая его элементы, биты validity и nextIndex.

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

  • hs.next может применяться только в анализаторах и дает ссылку на элемент стека с индексом hs.nextIndex. Если nextIndex не меньше размера стека, результатом оценки будет переход в состояние reject с ошибкой error.StackOutOfBounds. Если hs является l-value, индекс hs.next также будет l-value.

  • hs.last может применяться только в анализаторах и дает ссылку на элемент стека с индексом hs.nextIndex — 1, если такой элемент имеется. Если nextIndex меньше 1 или превышает размер, результатом оценки будет переход в состояние reject с установкой ошибки error.StackOutOfBounds. В отличие от hs.next ссылка никогда не является l-value.

  • hs.lastIndex может применяться только в анализаторах и дает 32-битовое целое число без знака, которое представляет индекс hs.nextIndex — 1. Если nextIndex = 0, оценка выражение ведет к неопределенному состоянию.

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

  • hs.push_front(int count) смещает hs «вправо» на count и первые count элементов становятся недействительными, а последние count элементов стека отбрасываются. Счетчик hs.nextIndex увеличивается на count. Аргумент count должен быть положительным целым числом, известным при компиляции. Результат имеет тип void.

  • hs.pop_front(int count) смещает hs «влево» на count (т. е. элемент count копируется в элемент 0). Последние count становятся недействительными, счетчик hs.nextIndex уменьшается на count. Аргумент count должен быть положительным целым числом, известным при компиляции. Результат имеет тип void.

Приведенный ниже псевдокод определяет поведение push_front и pop_front.

void push_front(int count) {
	for (int i = this.size-1; i >= 0; i -= 1) {
		if (i >= count) {
			this[i] = this[i-count];
		} else {
			this[i].setInvalid();
		}
	}
	this.nextIndex = this.nextIndex + count;
	if (this.nextIndex > this.size) this.nextIndex = this.size;
		// this.last, this.next, this.lastIndex корректируются с помощью this.nextIndex
}

void pop_front(int count) {
	for (int i = 0; i < this.size; i++) {
		if (i+count < this.size) {
			this[i] = this[i+count];
		} else {
			this[i].setInvalid();
		}
	}
	if (this.nextIndex >= count) {
		this.nextIndex = this.nextIndex - count;
	} else {
		this.nextIndex = 0;
	}
	// this.last, this.next, this.lastIndex корректируются с помощью this.nextIndex
}

Два стека заголовков можно сравнить на равенство (==) или неравенство (!=) лишь в том случае, когда они имеют элементы одного типа и совпадают по размеру. Два стека считаются одинаковыми, если все их соответствующие элементы равны друг другу. Значение nextIndex не учитывается при проверке равенства.

8.18. Операции над объединениями заголовков

Переменная, объявленная с типом union, исходно недействительна, например

header H1 {
	bit<8> f;
}
header H2 {
	bit<16> g;
}
header_union U {
	H1 h1;
	H2 h2;
}

U u; // u недействительна

Это также предполагает, что каждый из заголовков h1 — hn в объединении заголовков исходно недействителен. В отличие от заголовков объединение невозможно инициализировать. Однако validity для объединения заголовков можно обновить путем присваивания действительного заголовка одному из элементов объединения.

U u;
H1 my_h1 = { 8w0 }; // my_h1 действителенis valid
u.h1 = my_h1;		// u и u.h1 действительны

Можно также присвоить объединению список элементов

U u;
u.h2 = { 16w1 };	// u и u.h2 действительны

или установить биты validity напрямую

U u;
u.h1.setValid();	// u и u.h1 действительны
H1 my_h1 = u.h1;	// my_h1 действителен, но включает неопределенное значение

Отметим, что считывание неинициализированного заголовка дает неопределенное значение, даже если заголовок действителен. Более формально — если u является выражением типа union U с полями диапазона hi, для манипуляций с u можно использовать указанные ниже операции.

  • u.hi.setValid() устанавливает в битах validity значение true для заголовка hi и false для всех остальных, что означает возврат незаданного значения при чтении этих заголовков.

  • u.hi.setInvalid() — если бит validity для любого члена u имеет значение true, для него устанавливается значение false, что означает возврат незаданного значения при чтении любого заголовка.

Можно считать присваивание объединению заголовков

u.hi = e

эквивалентом

u.hi.setValid();
u.hi = e;

если заголовок e действителен и

u.hi.setInvalid();

в противном случае.

Разрешены операции присваивания между однотипными объединениями заголовков. Присваивание u1 = u2 копирует полное состояние объединения u2 в u1. Если объединение u2 действительно, в нем имеется тот или иной действительный заголовок u2.hi. Присваивание будет вести себя как u1.hi = u2.hi. Если u2 не является действительным, u1 станет недействительным (т. е. все действительные заголовки в u1 станут недействительными).

Метод u.isValid() возвращает true, если действителен любой из элементов объединения и false — в остальных случаях. Методы setValid() и setInvalid() не определены для объединений заголовков.

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

header_union IP {
	IPv4 ipv4;
	IPv6 ipv6;
}

struct Parsed_packet {
	Ethernet ethernet;
	IP ip;
}

parser top(packet_in b, out Parsed_packet p) {
	state start {
		b.extract(p.ethernet);
		transition select(p.ethernet.etherType) {
			16w0x0800 : parse_ipv4;
			16w0x86DD : parse_ipv6;
		}
	}

	state parse_ipv4 {
		b.extract(p.ip.ipv4);
		transition accept;
	}

	state parse_ipv6 {
		b.extract(p.ip.ipv6);
		transition accept;
	}
}

Можно также использовать объединения для анализа (выбранных) опций TCP, как показано ниже.

header Tcp_option_end_h {
	bit<8> kind;
}
header Tcp_option_nop_h {
	bit<8> kind;
}
header Tcp_option_ss_h {
	bit<8>	kind;
	bit<32> maxSegmentSize;
}
header Tcp_option_s_h {
	bit<8>	kind;
	bit<24> scale;
}
header Tcp_option_sack_h {
	bit<8>	kind;
	bit<8>	length;
	varbit<256>	sack;
}
header_union Tcp_option_h {
	Tcp_option_end_h	end;
	Tcp_option_nop_h	nop;
	Tcp_option_ss_h	ss;
	Tcp_option_s_h	s;
	Tcp_option_sack_h	sack;
	
typedef Tcp_option_h[10] Tcp_option_stack;

struct Tcp_option_sack_top {
	bit<8> kind;
	bit<8> length;
}

parser Tcp_option_parser(packet_in b, out Tcp_option_stack vec) {
	state start {
		transition select(b.lookahead<bit<8>>()) {
			8w0x0 : parse_tcp_option_end;
			8w0x1 : parse_tcp_option_nop;
			8w0x2 : parse_tcp_option_ss;
			8w0x3 : parse_tcp_option_s;
			8w0x5 : parse_tcp_option_sack;
		}
	}
	state parse_tcp_option_end {
		b.extract(vec.next.end);
		transition accept;
	}
	state parse_tcp_option_nop {
		b.extract(vec.next.nop);
		transition start;
	}
	state parse_tcp_option_ss {
		b.extract(vec.next.ss);
		transition start;
	}
	state parse_tcp_option_s {
		b.extract(vec.next.s);
		transition start;
	}
	state parse_tcp_option_sack {
		bit<8> n = b.lookahead<Tcp_option_sack_top>().length;
		// n указывает общий размер опции TCP SACK в байтах.
		// Размер varbit-поля sack в заголовке 
		// Tcp_option_sack_h составляет, таким образом, n-2 байт.
		b.extract(vec.next.sack, (bit<32>) (8 * n - 16));
		transition start;
	}
}

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

8.19. Вызовы методов и функций

Методы и функции можно вызывать с использованием показанного ниже синтаксиса.

expression
	: ...
	| expression '<' realTypeArgumentList '>' '(' argumentList ')'
	| expression '(' argumentList ')'
argumentList
	: /* пусто */
	| nonEmptyArgList
	;
nonEmptyArgList
	: argument
	| nonEmptyArgList ',' argument
	;
argument
	: expression	/* позиционный аргумент */
	| name '=' expression	/* именованный аргумент */
	| DONTCARE
	;
realTypeArgumentList
	: realTypeArg
	| realTypeArgumentList ',' typeArg
	;
realTypeArg
	: DONTCARE
	| typeRef
	;

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

extern void f(in bit<32> x, out bit<16> y);
bit<32> xa = 0;
bit<16> ya;
f(xa, ya);	// соответствие аргументов по порядку
f(x = xa, y = ya);	// соответствие аргументов по именам
f(y = ya, x = xa);	// соответствие аргументов в произвольном порядке
//f(x = xa);	-- ошибка - недостаточно аргументов
//f(x = xa, x = ya); -- ошибка - аргумент указан дважды
//f(x = xa, ya); ошибка - некоторые аргументы заданы именами
//f(z = xa, w = yz); ошибка - нет параметров с именем z и w
//f(x = xa, y = 0);	ошибка - аргумент y должен быть l-value

При вызовах используется соглашение copy-in/copy-out (6.7. Соглашения о вызовах). Для базовых функций тип аргументов можно явно указывать при вызове функции. Компилятор вставляет неявное приведение для аргументов in в методах и функциях, отмеченных в разделе 8.9. Приведение типов. Типы всех остальных аргументов должны точно совпадать с типами параметров.

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

Идентификатор _ (не имеет значения) можно использовать лишь в аргументах out, когда возвращаемое в аргументе значение игнорируется в последующих операциях. При использовании в базовых функциях и методах компилятор может отвергать программу, если он не способен вывести тип для аргумента don’t care (_).

8.20. Вызовы конструкторов

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

  • вызов конструктора, являющегося выражением, которое возвращает объект соответствующего типа;

  • использование инициаторов, как описано в параграфе 10.3. Создание экземпляров.

Синтаксис вызова конструктора похож на вызов функции и может включать именованные аргументы. Конструкторы полностью оцениваются (вычисляются) при компиляции (17. Абстрактная машина P4 — оценка). Поэтому все аргументы конструктора должны быть выражениями, вычисляемыми во время компиляции.

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

extern ActionProfile {
	ActionProfile(bit<32> size);	// конструктор
}
table tbl {
	actions = { /* тело опущено */ }
	implementation = ActionProfile(1024);	// вызов конструктора
}

8.21. Операции над типами, заданными type

Для значений с типами, заданными ключевым словом type, поддерживается лиш несколько операций:

  • присваивание l-value того же типа;

  • сравнение на равенство или неравенство, если исходный тип поддерживает такое сравнение;

  • приведение к исходному типу и обратно.

type bit<32> U32;
U32 x = (U32)0;			// требуется приведение
U32 y = (U32) ((bit<32>)x + 1);	// приведение нужно для арифметики
bit<32> z = 1;
bool b0 = x == (U32)z; 		// требуется приведение
bool b1 = (bit<32>)x == z;		// требуется приведение
bool b2 = x == y;			// приведение не требуется

8.22. Чтение неинициализированных значений и запись в недействительные заголовки

Как отмечено в параграфе 8.17. Операции над стеком заголовков, любая ссылка на элемент стека заголовков hs[index], где index — известное во время компиляции выражение (константа), должно приводить к ошибке, если индекс выходит за пределы диапазона. В этом параграфе также определено поведение при работе выражений hs.next и hs.last и описанное здесь поведение имеет приоритет по отношению ко всем прочим описаниям этих выражений.

Все упоминания элементов стека заголовков в этом параграфе применяются лишь к выражениям hs[index], где индекс является переменной, определяемой в процессе работы, а не при компиляции. Реализации P4 могут не поддерживать hs[index], где индекс определяется переменной во время выполнения, но при поддержке таких выражений реализации следует соответствовать описанному здесь поведению.

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

  • Чтение поля из недействительного (invalid) заголовка.

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

  • Чтение любого другого неинициализированного заголовка (например, поля struct), неинициализированной переменной в действии или элементе управления или параметра за пределами вызванного элемента управления или действия, которому не было присвоено значение в процессе выполнения действия или элемента управления (этот список не является исчерпывающим).

  • Чтение поля заголовка, который является элементом стека заголовков, где индекс выходит за пределы стека.

Вызов метода isValid() для элемента стека заголовков с индексом вне диапазона возвращает неопределенное логическое значение (true или false), но спецификация не требует определенного значения и даже согласованности значения при нескольких таких вызовах. Присваивание выходящего за пределы стека заголовков значения другому заголовку h ведет к неопределенному состоянию h во всех переменных заголовка, включая бит validity.

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

Для неинициализированного поля или переменной типа enum или error считывание назаданного значения может приводить к отличию от значений, определенных для этого типа. Такому неопределенному значению следует по-прежнему вести к предсказуемому поведению в случаях, когда будет подходить любое действительное значение. Например, следует соответствовать в приведенных ниже случаях.

  • При использовании в выражении select следует соответствовать default или _ в выражении набора ключей.

  • При использовании в качестве ключа с троичным match_kind в таблице следует соответствовать записи, где все биты поля имеют флаг don’t care.

  • При использовании в качестве ключа match_kind lpm в таблице следует соответствовать записи, где поле имеет префикс размером 0.

Рассмотрим ситуацию, где header_union u1 включает u1.h1 и u1.h2, а в данной точке программы u1.h1 является действительным, u1.h2 — недействительным. При попытке записи в поле недействительного заголовка u1.h2 может измениться любое (или все) поле действительного заголовка u1.h1. Такая запись не должна менять validity какого-либо из членов u1 или другие состояния, определенные в данный момент в системе, независимо от места определения этих состояний. При выполнении любого из действий:

  • запись в поле недействительного заголовка (обычного или элемента стека с индексом в пределах диапазона), не входящего в объединение заголовков;

  • запись в элемент стека заголовков с индексом за пределами диапазона;

  • вызов метода a method setValid() или setInvalid() для элемента стека заголовков с индексом за пределами диапазона;

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

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

8.23. Инициализация с принятыми по умолчанию значениями

Значения l-value можно инициализировать автоматически принятыми по умолчанию значениями подходящего типа с использованием синтаксиса … (7.3. Подразумеваемые значения). Значения типа struct, header, tuple можно инициализировать с использованием явно заданных и подразумеваемых значений, применяя нотацию … в инициализаторе выражения списка (не заданные явно поля будут инициализированы принятыми по умолчанию значениями). При инициализации struct, header и tuple с частичным заданием значений … нужно размещать в конце инициализатора.

struct S {
	bit<32> b32;
	bool b;
}

enum int<8> N0 {
	one = 1,
	zero = 0,
	two = 2
}

enum N1 {
	A, B, C, F
}

struct T {
	S s;
	N0 n0;
	N1 n1;
}

header H {
	bit<16> f1;
	bit<8> f2;
}

N0 n0 = ...;	// n0 инициализируется принятым по умолчанию значением 0
N1 n1 = ...;	// n1 инициализируется принятым по умолчанию значением N1.A
S s0 = ...;	// s0 инициализируется принятым по умолчанию значением { 0, false }
S s1 = { 1, ... };	// s1 инициализируется значением { 1, false }
S s2 = { b = true, ... }; // s2 инициализируется значением { 0, true }
T t0 = ...;	// t0 инициализируется значением { { 0, false }, 0, N1.A }
T t1 = { s = ..., ... }; // t1 инициализируется значением { { 0, false }, 0, N1.A }
T t2 = { s = ... }; // ошибка - нет инициализатора для полей n0 и n1
tuple<N0, N1> p = { ... }; // p инициализируется принятым по умолчанию значением { 0, N1.A }
T t3 = { ..., n0 = 2}; // ошибка - ... должно быть в конце
H h1 = ...;	// h1 инициализируется недействительным заголовком
H h2 = { f2=5, ... };	// h2 инициализируется действительным заголовком, f1 0, f2 5
H h3 = { ... };	// h3 инициализируется действительным заголовком, f1 0, f2 0

9. Объявление функции

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

functionDeclaration
	: functionPrototype blockStatement
	;

functionPrototype
	: typeOrVoid name optTypeParameters '(' parameterList ')'
	;

Ниже приведен пример функции, возвращающей большее из двух 32-битовых значений.

bit<32> max(in bit<32> left, in bit<32> right) {
	if (left > right)
		return left;
	return right;
}

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

10. Объявление констант и переменных

10.1. Константы

Для определения констант применяется показанный ниже синтаксис.

constantDeclaration
	: optAnnotations CONST typeRef name '=' initializer ';'
	;

initializer
	: expression
	;

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

const bit<32> COUNTER = 32w0x0;
struct Version {
	bit<32> major;
	bit<32> minor;
}
const Version version = { 32w0, 32w0 };

10.2. Переменные

Локальные переменные объявляются с типом и именем, а также могут указывать инициализатор и аннотацию.

variableDeclaration
	: annotations typeRef name optInitializer ';'
	| typeRef name optInitializer ';'
	;

optInitializer
	: /* пусто */
	| '=' initializer
	;

Объявления переменных без инициализатора не инициализируются (за исключением заголовков и связанных с ними типов, которые инициализируются как недействительные (invalid) так же, как описано для параметров out в параграфе 6.7. Соглашения о вызовах). Язык вносит некоторые ограничения на типы переменных — можно применять большинство типов P4, которые могут быть записаны явно (например, базовые типы, struct, header, стеки заголовков, tuple). Однако невозможно объявить переменные типов, которые синтезируются компилятором (например, set). Кроме того, переменные типов parser, control, package, extern должны объявляться с инициализатором (10.3. Создание экземпляров). Считывание значения неинициализированной переменной дает неопределенный результат. Компиляторам следует пытаться детектировать такие ситуации и выдавать предупреждения.

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

  • оператор block;

  • состояние анализатора;

  • тело действия (action);

  • блок исполнения управляющего блока;

  • список локальных объявлений анализатора;

  • список локальных объявлений элемента управления.

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

10.3. Создание экземпляров

Создание экземпляров похоже на объявление переменных, но оно зарезервировано для типов с конструктором (внешние объекты, блоки управления, анализаторы и пакеты).

instantiation
	: typeRef '(' argumentList ')' name ';'
	| annotations typeRef '(' argumentList ')' name ';'
	;

Создание экземпляра записывается как вызов конструктора с указанием имени и всегда выполняется во время компиляции (17.1. Известные при компиляции значения). Результатом служит создание объекта с указанным именем и его привязка к результату вызова конструктора. Отметим, что аргументы создания экземпляра можно задавать именами. Например, экземпляр гипотетического банка счетчиков можно создать, как показано ниже.

// Из библиотеки платформы
enum CounterType {
	Packets,
	Bytes,
	Both
}
extern Counter {
	Counter(bit<32> size, CounterType type);
	void increment(in bit<32> index);
}
// Программа пользователя
control c(/* параметры опущены */) {
	Counter(32w1024, CounterType.Both) ctr;	// создание экземпляра
	apply { /* тело опущено */ }
}

10.3.1. Ограничения для создания экземпляров на верхнем уровне

Программы P4 не могут создавать элементы управления и синтаксические анализаторы в пакете верхнего уровня (top-level package). Это ограничение нацелено на то, чтобы обеспечить размещение большинства состояний в самой архитектуре или локальном элементе управления синтаксического анализатора. Ниже приведен пример некорректного создания экземпляра.

// Программа
control c(/* параметры опущены */) { /* тело опущено */ }
c() c1;	// Недопустимое создание экземпляра на верхнем уровне

Элемент управления c1 создается на верхнем уровне, что недопустимо. Отметим, что объявление на верхнем уровне констант и создание экземпляров внешних объектов являются корректными действиями.

11. Операторы

Каждый оператор P4 (кроме block) должен завершаться точкой с запятой (;). Операторы могут указываться внутри:

  • состояний анализатора;

  • блоков управления;

  • действий.

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

statement
	: assignmentOrMethodCallStatement
	| conditionalStatement
	| emptyStatement
	| blockStatement
	| exitStatement
	| returnStatement
	| switchStatement
	;

assignmentOrMethodCallStatement
	: lvalue '(' argumentList ')' ';'
	| lvalue '<' typeArgumentList '>' '(' argumentList ')' ';'
	| lvalue '=' expression ';'
	;

Кроме того, анализаторам следует поддерживать оператор transition (Section 12.5).

11.1. Оператор присваивания

В операторах присваивания (=) сначала проверяется, относится ли левое выражение к l-value, затем определяется значение правого выражения и результат копируется в l-value. Производные типы (например, struct) копируются рекурсивно с копированием всех полей заголовка, включая биты validity. Присваивание не определено для внешних объектов.

11.2. Пустой оператор

Пустой оператор имеет вид ; (нет операций).

emptyStatement
	: ';'
	;

11.3. Оператор блока

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

blockStatement
	: optAnnotations '{' statOrDeclList '}'
	;

statOrDeclList
	: /* пусто */
	| statOrDeclList statementOrDeclaration
	;

statementOrDeclaration
	: variableDeclaration
	| constantDeclaration
	| statement
	| instantiation
	;

11.4. Оператор возврата

Оператор return незамедлительно прерывает выполнение действия, функции или блока управления. Оператор return не разрешается использовать в анализаторах. В функциях с возвращаемым значением за оператором return следует выражение, тип которого должен соответствовать объявленному типу функции. Любые действия в стиле copy-out, заданные параметрами out или inout во включающем оператор действии, функции или элементе управления, происходят после выполнения оператора return (6.7. Соглашения о вызовах).

returnStatement
	: RETURN ';'
	| RETURN expression ';'
	;

11.5. Оператор выхода

Оператор exit незамедлительно прерывает выполнение всех выполняющихся в данное время блоков. Прерывается текущее действие (если оператор вызван внутри action), текущий элемент управления и все вызывающие их. Оператор exit нельзя использовать в анализаторах и функциях.

Любые действия copy-out, заданные параметрами с направлением out или inout включающего оператор действия или элемента управления и всех вызывающих его, выполняются после выполнения оператора exit (6.7. Соглашения о вызовах.

exitStatement
	: EXIT ';'
	;

11.6. Условный оператор

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

conditionalStatement
	: IF '(' expression ')' statement
	| IF '(' expression ')' statement ELSE statement
	;

Во вложенных конструкциях с условиями else относится к внутреннему (наиболее близкому) оператору if, у которого нет оператора else.

11.7. Оператор выбора

Оператор switch можно применять только в блоках управления.

switchStatement
	: SWITCH '(' expression ')' '{' switchCases '}'
	;

switchCases
	: /* пусто */
	| switchCases switchCase
	;

switchCase
	: switchLabel ':' blockStatement
	| switchLabel ':'	// fall-through
	;

switchLabel
	: name
	| DEFAULT
	;

Выражение в операторе switch должно быть результатом вызова таблицы (13.2.2. Вызов блока СД).

Если за меткой оператора switch нет оператора блока, выполняется переход к следующей метке. Однако при наличии оператора блока переход к следующей метке не происходит. Это отличается от операторов выбора в C, где для предотвращения перехода к следующей метке требуется break. Допускается отсутствие действий для некоторых меток и отсутствие метки default. Если в процессе работы не найдено совпадений, просто продолжается выполнение программы. Повторение метки в операторе switch не допускается.

switch (t.apply().action_run) {
	action1:	// переход к action2:
	action2: { /* тело опущено */ }
	action3: { /* тело опущено */ }	// нет перехода от action2 к action3
	default: { /* тело опущено */ }
}

Отметим, что метка default в операторе switch используется для выполнения того или иного действия, независимо от нахождения или отсутствия ключа в таблице. Метка default не указывает отсутствие таблицы и заданное по умолчанию действие (default_action) выполняется. Метка default (при наличии) должна быть последней.

12. Анализ пакета

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

12.1. Состояния анализатора

 
Рисунок 8. Структура FSM.

Синтаксический анализатор P4 описывает конечный автомат с одним стартовым и двумя финальными состояниями. Начальное состояние всегда именуется start. Два финальных состояния называются accept (успешный анализ) и reject (отказ при анализе). Состояние start является частью анализатора, а состояния accept и reject отличаются от состояний, задаваемых программистом, и логически находятся за пределами анализатора. На рисунке 8 показана общая структура конечного автомата анализатора (FSM).

12.2. Объявление анализатора

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

parserTypeDeclaration
	: optAnnotations PARSER name optTypeParameters
	 '(' parameterList ')'
	;

parserDeclaration
	: parserTypeDeclaration optConstructorParameters
	  '{' parserLocalElements parserStates '}'
	;

parserLocalElements
	: /* пусто */
	| parserLocalElements parserLocalElement
	;

parserStates
	: parserState
	| parserStates parserState
	;

Описание optConstructorParameters, полезных при создании параметризованных анализаторов, приведено в разделе 14. Параметризация.

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

parser P<H>(inout H data) { /* тело опущено */ }

Поэтому при использовании в контексте parserDeclaration правило создания parserTypeDeclaration не должно давать параметры типа.

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

Объявления состояний описаны ниже. Перед состояниями анализатор может также указывать локальные элементы, которыми могут быть константы и переменные, а также создание экземпляров объектов, которые могут применяться в анализаторе. Это могут быть экземпляры внешних объектов или другие анализаторы, вызываемые как подпрограммы. Однако не допускается создание в анализаторе блоков управления.

parserLocalElement
	: constantDeclaration
	| variableDeclaration
	| valueSetDeclaration
	| instantiation
	;

Пример с полным объявлением анализатора приведен в параграфе 5.3. Полная программа VSS.

12.3. Абстрактная машина синтаксического анализа

Семантику синтаксического анализатора P4 можно выразить через абстрактную машину, манипулирующую структурой данных ParserModel. Ниже эта машина описана псевдокодом. Выполнение анализатора начинается из состояния start и завершается по достижении состояния reject или accept.

ParserModel {
	error	parseError;
	onPacketArrival(packet p) {
		ParserModel.parseError = error.NoError;
		goto start;
	}
}

Архитектура должна задавать поведение при достижении состояний accept и reject. Например, можно задать отбрасывание всех пакетов по достижении состояния reject без дальнейшей обработки. Другим вариантом может быть передача таких пакетов следующему за анализатором блоку с внутренними метаданными, показывающими состояние reject и причину его.

12.4. Состояния анализатора

Состояния анализатора объявляются в виде

parserState
	: optAnnotations STATE name
	'{' parserStatements transitionStatement '}'
	;

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

  • объявления локальных переменных;

  • операторы присваивания;

  • вызовы методов, включая:

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

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

  • переходы в другое состояние (12.5. Операторы смены состояния (перехода)).

Синтаксис операторов анализатора использует приведенную ниже грамматику.

parserStatements
	: /* пусто */
	| parserStatements parserStatement
	;

parserStatement
	: assignmentOrMethodCallStatement
	| directApplication
	| variableDeclaration
	| constantDeclaration
	| parserBlockStatement
	| emptyStatement
	;

parserBlockStatement
	: optAnnotations '{' parserStatements '}'
	;

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

В ParserModel операторы в том или ином состоянии выполняются последовательно.

12.5. Операторы смены состояния (перехода)

Последним оператором в состоянии анализатора является необязательный оператор transition, переводящий элемент управления в иное состояние (возможно, accept или reject). Синтаксис оператора transition покакан ниже.

transitionStatement
	: /* пусто */
	| TRANSITION stateExpression
	;

stateExpression
	: name ';'
	| selectExpression
	;

Выполнение опреатора transition вызывает оценку (вычисление) stateExpression и переход в соответствующее состояние. В ParserModel семантику перехода можно формализовать в виде

goto eval(stateExpression)

Например, оператор

transition accept;

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

Если тело блока состояний не включает оператора transition, подразумевается переход в состояние reject.

12.6. Выражения для выбора

Выражение select ведет к выбору состояния и использует показанный ниже синтаксис.

selectExpression
	: SELECT '(' expressionList ')' '{' selectCaseList '}'
	;

selectCaseList
	: /* пусто */
	| selectCaseList selectCase
	;

selectCase
	: keysetExpression ':' name ';'
	;

selectCase
	: keysetExpression ':' name ';'
	;

Если в выражении select expressionList имеет типа tuple<T>, каждое из выражений keysetExpression должно иметь тип set<tuple<T>>.

В ParserModel выражение select

select(e) {
	ks[0]: s[0];
	ks[1]: s[1];
	/* остальные варианты опущены */
	ks[n-2]: s[n-1];
	_ : sd;	// ks[n-1] используется по умолчанию
}

можно представить в виде псевдокода

key = eval(e);
for (int i=0; i < n; i++) {
	keyset = eval(ks[i]);
	if (keyset.contains(key)) return s[i];
}
verify(false, error.NoMatch);

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

Приведенный пример предполагает, что все метки после default или _ label не используются. Компилятор в таких случаях должен выдавать предупреждение. Это показывает важное различие между выражениями select и операторами switch в других языках, поскольку keyset в выражениях select могут «перекрываться».

Типичным примером использования select является сравнение недавно извлеченного поля заголовка с набором констант, как показано ниже

header IPv4_h { bit<8> protocol; /* другие поля опущены */ }
struct P { IPv4_h ipv4; /* другие поля опущены */ }
P headers;
select (headers.ipv4.protocol) {
	8w6	: parse_tcp;
	8w17 	: parse_udp;
	_	: accept;
}
select (p.tcp.port) {
	16w0 &&& 16w0xFC00: well_known_port;
	_: other_port;
}

Выражение 16w0 &&& 16w0xFC00 описывает набор 16-битовых значений и 0 в шести старших битах.

Некоторые платформы могут поддерживать наборы значений в анализаторах (12.11. Набор значений анализатора). Для параметра типа T в наборе значений типом набора будет set<T>. Тип набора значений должен совпадать с типом всех других keysetExpression в данном выражении select и при наличии расхождений компилятор должен выдавать ошибку. В наборе значений должен использоваться тип bit<>, tuple или struct.

Например, чтобы позволить API плоскости управления задавать порты TCP в процессе работы, можно использовать

struct vsk_t {
	@match(ternary)
	bit<16> port;
}
value_set<vsk_t>(4) pvs;
select (p.tcp.port) {
	pvs: runtime_defined_port;
	_: other_port;
}

Приведенный пример позволяет API в процессе работы заполнить до 4 разных keysetExpression в value_set. Если value_принимает в качестве параметра типа struct, API может использовать имена полей struct для указания объектов в наборе значений. Тип совпадения для поля struct задается аннотацией @match. Если эта аннотация не задана для поля struct, предполагается @match(exact). Одиночное поле без точного совпадения должно помещаться в struct самим полем, желательно с аннотацией @match.

12.7. Оператор verify

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

extern void verify(in bool condition, in error err);

Если первый аргумент имеет значение true, выполнение опереатора не имеет побочных эффектов. Однако при значении false оператор вызывает незмедлительный переход в состояние reject с прерыванием анализа и установкой в parserError, связанного с анализатором, значения второго аргумента. В ParserModel семантика verify имеет вид

ParserModel.verify(bool condition, error err) {
	if (condition == false) {
		ParserModel.parserError = err;
		goto reject;
	}
}

12.8. Извлечение данных

Основная библиотека P4 включает объявление встроенного extern типа packet_in, представляющего входны пакеты из сети. Этот тип является особым и пользователь не может явно создать его экземпляр. Архитектура представляет отдельный экземпляр packet_in при создании каждого экземпляра анализатора.

extern packet_in {
	void extract<T>(out T headerLvalue);
	void extract<T>(out T variableSizeHeader, in bit<32> varFieldSizeBits);
	T lookahead<T>();
	bit<32> length();	// Метод поддерживается не всеми архитектурами
	void advance(bit<32> bits);
}

Для извлечения данных из пакета, представленного аргументом b типа packet_in, анализатор вызывает методы извлечения для b. Имеется два варианта метода извлечения — с одним аргументом для заголовков фиксированного размера и с двумя аргументами для заголовков переменного размера. Поскольку эти операции могут приводить к отказам проверок во время работы, выполнение их возможно лишь из синатксических анализаторов.

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

Некоторые платформы могут выполнять обработку «на лету» (cut-through), т. е. начинать обработку до того, как станет известен размер пакета (пакет еще не принят полностью). На таких платформах вызов метода packet_in.length() не может быть реализован и попытки таких вызовов должны помечаться как ошибки (во время компиляции back-end или при попытке загрузки скомпилированной программы P4 на платфоре, не поддерживающей этот метод).

В ParserModel семантику packet_in можно представить с использованием абстрактной модели пакетов

packet_in {
	unsigned nextBitIndex;
	byte[] data;
	unsigned lengthInBits;
	void initialize(byte[] data) {
		this.data = data;
		this.nextBitIndex = 0;
		this.lengthInBits = data.sizeInBytes * 8;
	}
	bit<32> length() { return this.lengthInBits / 8; }
}

12.8.1. Извлечение при фиксированном размере

Метод извлечения с одним аргументом, применяемый для заголовков фиксированного размера, объявлен в форме

void extract<T>( out T headerLeftValue);

Выражение headerLeftValue должно оцениваться в l-value (6.6. Выражения для левой части) типа header с фиксированным размером. При успешном выполнении метода headerLvalue заполняется данными из пакета и для бита validity устанавливается значение true. Метод может приводить к отказам, например, при нехватке в пакете битов для заполнения заголовка. Ниже приведен фрагмент программы для извлечения заголовка Ethernet.

struct Result { Ethernet_h ethernet;	/* другие поля опущены */ }
parser P(packet_in b, out Result r) {
	state start {
		b.extract(r.ethernet);
	}
}

В ParserModel семантику извлечения с одним аргументом можно представить приведенным ниже псевдокодом. Специальный идентификатор valid$ служит для скрытого флага validity, isNext$ — для индикации получения l-value с использованием next, а nextIndex$ — для указания соответствующих свойств стека заголовков.

void packet_in.extract<T>(out T headerLValue) {
	bitsToExtract = sizeofInBits(headerLValue);
	lastBitNeeded = this.nextBitIndex + bitsToExtract;
	ParserModel.verify(this.lengthInBits >= lastBitNeeded, error.PacketTooShort);
	headerLValue = this.data.extractBits(this.nextBitIndex, bitsToExtract);
	headerLValue.valid$ = true;
	if headerLValue.isNext$ {
		verify(headerLValue.nextIndex$ < headerLValue.size, error.StackOutOfBounds);
		headerLValue.nextIndex$ = headerLValue.nextIndex$ + 1;
	}
	this.nextBitIndex += bitsToExtract;
}

12.8.2. Извлечение при переменном размере

Извлечение с двумя аргументами для заголовков переменного размера объявляется в P4 в форме

void extract<T>(out T headerLvalue, in bit<32> variableFieldSize);

Выражение headerLvalue должно быть l-value и представлять заголовок с единственным полем varbit. Выражение variableFieldSize должно оцениваться в значение bit<32>, указывающее число битов, извлекаемых в уникальное поле varbit переменной header (т. е. это не размер заголовка, а размер поля varbit). В ParserModel семантику извлечения с двумя аргументами можно выразить псевдокодом, приведенным ниже.

void packet_in.extract<T>(out T headerLvalue,
					in bit<32> variableFieldSize) {
	// платформы могут, но не обязаны включать строку проверки 
	// verify(variableFieldSize[2:0] == 0, error.ParserInvalidArgument);
	bitsToExtract = sizeOfFixedPart(headerLvalue) + variableFieldSize;
	lastBitNeeded = this.nextBitIndex + bitsToExtract;
	ParserModel.verify(this.lengthInBits >= lastBitNeeded, error.PacketTooShort);
	ParserModel.verify(bitsToExtract <= headerLvalue.maxSize, error.HeaderTooShort);
	headerLvalue = this.data.extractBits(this.nextBitIndex, bitsToExtract);
	headerLvalue.varbitField.size = variableFieldSize;
	headerLvalue.valid$ = true;
	if headerLValue.isNext$ {
		verify(headerLValue.nextIndex$ < headerLValue.size, error.StackOutOfBounds);
		headerLValue.nextIndex$ = headerLValue.nextIndex$ + 1;
	}
	this.nextBitIndex += bitsToExtract;

}

Приведенный ниже пример показывает один из способов анализа опций IPv4 путем разделения заголовка IPv4 на два отдельных объекта header.

// Заголовок IPv4 без опций
header IPv4_no_options_h {
	bit<4>		version;
	bit<4>		ihl;
	bit<8>		diffserv;
	bit<16>	totalLen;
	bit<16>	identification;
	bit<3>		flags;
	bit<13>	fragOffset;
	bit<8>		ttl;
	bit<8>		protocol;
	bit<16>	hdrChecksum;
	bit<32>	srcAddr;
	bit<32>	dstAddr;
}
header IPv4_options_h {
	varbit<320> options;
}
struct Parsed_headers {
	// некоторые поля опущены
	IPv4_no_options_h ipv4;
	IPv4_options_h	ipv4options;
}

error { InvalidIPv4Header }

parser Top(packet_in b, out Parsed_headers headers) {
	// некоторые состояния опущены
	state parse_ipv4 {
		b.extract(headers.ipv4);
		verify(headers.ipv4.ihl >= 5, error.InvalidIPv4Header);
		transition select (headers.ipv4.ihl) {
			5: dispatch_on_protocol;
			_: parse_ipv4_options;
		}
	}
	state parse_ipv4_options {
		// используется информация из заголовка IPv4 для расчета
		// числа извлекаемых битов
		b.extract(headers.ipv4options,
				(bit<32>)(((bit<16>)headers.ipv4.ihl - 5) * 32));
		transition dispatch_on_protocol;
	}
}

12.8.3. Предварительный просмотр

Метод lookahead обеспечиваемый абстракцией packet_in оценивает набор битов из входящего пакета без указателя nextBitIndex. Подобно extract, он будет переводить в состояние reject и возвращать ошибку, если в пакете недостаточно битов. Вызов метода имеет вид

b.lookahead<T>()

где T должен быть типом фиксированного размера. При успешной оценке lookahead возвращает значение типа T. В ParserModel семантика lookahead может выть выражена приведенным ниже псевдокодом.

T packet_in.lookahead<T>() {
	bitsToExtract = sizeof(T);
	lastBitNeeded = this.nextBitIndex + bitsToExtract;
	ParserModel.verify(this.lengthInBits >= lastBitNeeded, error.PacketTooShort);
	T tmp = this.data.extractBits(this.nextBitIndex, bitsToExtract);
	return tmp;
}

Пример с опциями TCP из параграфа 8.18. Операции над объединениями заголовков также служит иллюстрацией к применению lookahead.

state start {
	transition select(b.lookahead<bit<8>>()) {
		0: parse_tcp_option_end;
		1: parse_tcp_option_nop;
		2: parse_tcp_option_ss;
		3: parse_tcp_option_s;
		5: parse_tcp_option_sack;
	}
}
// некоторые состояния опущены
state parse_tcp_option_sack {
	bit<8> n = b.lookahead<Tcp_option_sack_top>().length;
	b.extract(vec.next.sack, (bit<32>) (8 * n - 16));
	transition start;
}

12.8.4. Пропуск битов

P4 обеспечивает два способа пропуска битов во входном пакете без передачи их в заголовок (header). Один способ заключается в извлечение в переменную _, явно задающую тип данных

b.extract<T>(_)

Другим способом служит использование метода advance, когда число пропускаемых битов известно. В ParserModel метод advance можно выразить приведенным ниже псевдокодом.

void packet_in.advance(bit<32> bits) {
	// платформы могут, но не обязаны включать строку проверки 
	// verify(bits[2:0] == 0, error.ParserInvalidArgument);
	lastBitNeeded = this.nextBitIndex + bits;
	ParserModel.verify(this.lengthInBits >= lastBitNeeded, error.PacketTooShort);
	this.nextBitIndex += bits;
}

12.9. Стеки заголовков

Стеки заголовков имеют два свойства — next и last, которые можно использовать при анализе. Рассмотрим пример, определяющий стек для представления пакетов, содержащих до 10 заголовков MPLS.

header Mpls_h {
	bit<20> label;
	bit<3>	tc;
	bit	bos;
	bit<8>	ttl;
}
Mpls_h[10] mpls;

Выражение mpls.next представляет l-value типа Mpls_h со ссылкой на элемент стека заголовков. Исходно mpls.next указывает первый элемент стекаи автоматически перемещается вперед при каждом успешном извлечении заголовка. Свойство mpls.last указывает элемент, непосредственно предшествующий следующему, если такой элемент существует. Попытка доступа к mpls.next при nextIndex не меньше размера стека вызывает переход в состояние reject and и ошибку error.StackOutOfBounds. Аналогично, попытка доступа к mpls.last при nextIndex = 0 вызывает переход в состояние reject и ошибку error.StackOutOfBounds. Ниже приведен пример простого анализатора для обработки MPLS.

struct Pkthdr {
	Ethernet_h ethernet;
	Mpls_h[3] mpls;
	// другие заголовки опущены
}

parser P(packet_in b, out Pkthdr p) {
	state start {
		b.extract(p.ethernet);
		transition select(p.ethernet.etherType) {
			0x8847: parse_mpls;
			0x0800: parse_ipv4;
		}
	}
	state parse_mpls {
		b.extract(p.mpls.next);
		transition select(p.mpls.last.bos) {
			0: parse_mpls; // создает цикл
			1: parse_ipv4;
		}
	}
	// другие состояния опущены
}

12.10. Субанализаторы

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

parser callee(packet_in packet, out IPv4 ipv4) { /* тело опущено */ }
parser caller(packet_in packet, out Headers h) {
	callee() subparser;
 	// экземпляр вызываемого анализатора
	state subroutine {
		subparser.apply(packet, h.ipv4);	// вызов субанализатора
		transition accept;	// если субанализатор завершился состоянием accept
	}
}

Семантику вызова субанализатора можно описать следующим образом (рисунок 9):

  • состояние, вызывающее субанализатор делится на два полусостояния в операторе вызова анализатора;

  • верхняя половина включает переход в состояние start субанализатора;

  • состояние субанализатора accept ведет к переходу в нижнюю половину текущего состояния;

  • состояние субанализатора reject переводит текущий анализатор в состояние reject.

Рисунок 9. Семантика вызова субанализатору — сверху исходная программа, снизу эквивалент.

Поскольку P4 требует объявления перед использованием, невозможно создать (взаимно) рекурсивные анализаторы.

Архитектура может (статически или динамически) ограничивать число состояний, которые анализатор может проходить при разборе пакета. Например, компилятор для конкретной платформы может отвергать анализаторы с циклом, который нельзя развернуть во время компиляции. Если анализатор прерывает работу динамически в результате исчерпания разрешенного для обработки времени, ему следует перейти в состояние reject с ошибкой error.ParserTimeout.

12.11. Набор значений анализатора

В некоторых случаях значения, определяющие переход анализатора из одного состояния в другое, нужно определяеть во время работы. MPLS является одним из примеров, где поле метки MPLS служит для определения того, что следует за тегом MPLS и это отображение может меняться во время работы. Для поддержки такой функциональности в P4 используется набор значений анализатора (Parser Value Set) — именованный набор значений с API среду выполнения для добавления и удаления элементов. Наборы значений объявляются локально в анализаторе. Значения следует объявлять до ссылки на них в keysetExpression и они могут применяться в выражениях select. Синтаксис объявления показан ниже.

valueSetDeclaration
	: optAnnotations
		VALUESET '<' baseType '>' '(' expression ')' name ';'
	| optAnnotations
		VALUESET '<' tupleType '>' '(' expression ')' name ';'
	| optAnnotations
		VALUESET '<' typeName '>' '(' expression ')' name ';'
	;

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

value_set<bit<16>>(4) pvs;

создает value_set размера 4 с записями типа bit<16>.

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

13. Блоки управления

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

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

controlDeclaration
	: controlTypeDeclaration optConstructorParameters
		/* controlTypeDeclaration не может включать параметры типа */
		'{' controlLocalDeclarations APPLY controlBody '}'
	;

controlLocalDeclarations
	: /* пусто */
	| controlLocalDeclarations controlLocalDeclaration
	;

controlLocalDeclaration
	: constantDeclaration
	| variableDeclaration
	| actionDeclaration
	| tableDeclaration
	| instantiation
	;

controlBody
	: blockStatement
	;

В блоках управления не допускается создание экземпляров анализаторов. Описание параметров optConstructorParameters, которые могут применяться для создания параметризованных блоков управления, дано в разделе 14. Параметризация.

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

control C<H>(inout H data) { /* тело опущено */ }

P4 не поддерживает исключений для потока управления внутри элементов управления. Единственным оператором, имеющим нелокальный эффект для потока управления, является оператор exit, незамедлительно прерывающий выполнение содержащего его блока. Т. е. здесь нет эквивалента оператора verify или состояния reject в анализаторах. Поэтому все ошибки должны явно обрабатываться программой.

13.1. Действия

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

actionDeclaration
	: optAnnotations ACTION name '(' parameterList ')' blockStatement
	;

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

action Forward_a(out bit<9> outputPort, bit<9> port) {
	outputPort = port;
}

Рисунок 10. Действия включают код (P4) и данные, задаваемые плоскостью управления. Параметры задаются плоскостью данных.

Параметры действия не могут иметь тип extern. Не имеющие направления параметры действия (например, port в предыдущем примере) указывают «данные действия». Все такие параметры должны указываться в конце списка параметров. При использовании в таблице СД (13.2.1.2. Действия) эти параметры будут предоставляться плоскостью управления.

Тело действия состоит из операторов и объявлений. Операторы switch не допускаются в действиях — грамматика разрешает их, но семантическим проверкам следует отвергать. Некоторые платформы могут вносить дополнительные ограничения, например, разрешать лишь линейный код без условных операторов и выражений.

13.1.1. Вызов действия

Действия могут выполняться двумя способами.

  • Неявно таблицами в процессе обработки СД.

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

13.2. Таблицы

Таблица описывает блок «сопоставление-действие» (СД). Структура таблицы показана на рисунке 11.

Рисунок 11. Поток данных блока СД.

Обработка пакета с использованием таблицы СД состоит из нескольких этапов:

  • создание ключа;

  • поиск ключа в таблице (match), результатом чего является действие (action);

  • выполнение действия (action) над входными данными, ведущее к изменению данных.

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

Таблица поиска является конечным отображением, содержимое которого меняется асинхронно (чтение и запись) плоскостью управления целевой платформы с использованием отдельного API плоскости управления (рисунок 11). Отметим, что термин «таблица» служит как для обозначения таблиц в программах P4, так и внутренних таблиц целевой платформы. Для устранения путаницы иногда будут использоваться термин «блок СД».

Синтаксически таблица определяется в терминах множества свойств «ключ-значение». Некоторые из этих свойств являются «стандартными», но набор свойств может быть при необходимости расширен компилятором платформы.

tableDeclaration
	: optAnnotations TABLE name '{' tablePropertyList '}'
	;

tablePropertyList
	: tableProperty
	| tablePropertyList tableProperty
	;

tableProperty
	: KEY '=' '{' keyElementList '}'
	| ACTIONS '=' '{' actionList '}'
	| CONST ENTRIES '=' '{' entriesList '}' /* неизменяемые записи */
	| optAnnotations CONST nonTableKwName '=' initializer ';'
	| optAnnotations nonTableKwName '=' initializer ';'
	;

nonTableKwName
	: IDENTIFIER
	| TYPE_IDENTIFIER
	| APPLY
	| STATE
	| TYPE
	;

Стандартные свойства таблицы включают:

  • ключ — выражение, описывающее создание ключа для поиска в таблице;

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

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

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

  • размер — целое число, указывающее желаемый размер таблицы.

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

Таблицы могут также включать зависимые от архитектуры свойства (13.2.1.6. Дополнительные свойства).

Свойства, указанные как const, не могут динамически изменяться плоскостью управления. Свойства key, actions, size всегда являются постоянными, поэтому для них не требуется ключевое слово const.

13.2.1. Свойства таблицы

13.2.1.1. Ключи

Ключ является свойством таблицы, задающим значения плоскости данных, используемые для поиска записей в таблице. Ключ представляет собой список пар (e : m), где e — выражение, описывающее данные для сопоставления с таблицей, а m — константа match_kind, описывающая алгоритм сопоставления (7.1.3. Тип match_kind).

keyElementList
	: /* пусто */
	| keyElementList keyElement
	;

keyElement
	: expression ':' name optAnnotations ';'
	;

Рассмотрим в качестве примера фрагмент программы

table Fwd {
	key = {
		ipv4header.dstAddress : ternary;
		ipv4header.version	: exact;
	}
	// другие поля опущены
}

Здесь ключ содержит два поля заголовка ipv4header — dstAddress и version, а match_kind служит трем целям:

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

  • создание API плоскости управления для заполнения таблицы;

  • использование компилятором back-end при выделении ресурсов для реализации таблицы.

Основная библиотека P4 содержит три предопределенных идентификатора match_kind.

match_kind {
	exact,
	ternary,
	lpm
}

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

Если таблица не имеет свойства key, она не будет таблицей поиска и будет включать лишь принятое по умолчанию действие, т. е. являться пустым отображением.

Каждый элемент ключа может иметь аннотацию @name, используемую для создания видимого плоскости управления имени для поля ключа.

13.2.1.2. Действия

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

actionList
	: /* пусто */
	| actionList optAnnotations actionRef ';'
	;

actionRef
	: prefixedNonTypeName
	| prefixedNonTypeName '(' argumentList ')'
;

Для иллюстрации вернемся к примеру VSS из параграфа 5.1. Архитектура VSS.

action Drop_action() {
	outCtrl.outputPort = DROP_PORT;
}
action Rewrite_smac(EthernetAddress sourceMac) {
	headers.ethernet.srcAddr = sourceMac;
}
table smac {
	key = { outCtrl.outputPort : exact; }
	actions = {
		Drop_action;
		Rewrite_smac;
	}
}
  • Записи таблицы smac могут включать два действия — Drop_action и Rewrite_mac.

  • Действие Rewrite_smac имеет один параметр — sourceMac, который задается плоскостью управления.

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

action a() {}
control c() {
	action a() {}
	// Некорректная таблица - имена двух действий совпадают
	table t { actions = { a; .a; } }
}

Каждый параметр с направлением (in, inout, out) должен быть привязан в списке спецификации действий, а параметры без направления не могут быть привязаны к этому списку. Выражения, представленные как аргументы, не оцениваются до вызова действия.

action a(in bit<32> x) { /* тело опущено */ }
bit<32> z;
action b(inout bit<32> x, bit<8> data) { /* тело опущено */ }
table t {
	actions = {
		// a; -- недействительно, параметр x должен быть привязан
		a(5);	// привязка параметра x из a - 5
		b(z);	// привязка параметра x из b - z
		// b(z, 3); недействительная привязка параметра без направления
		// b(); -- недействительно, параметр x должен быть привязан
	}
}
13.2.1.3. Принятое по умолчанию действие

Принятое по умолчанию действие вызывается для таблицы блоком СД автоматически, если в таблице не найдено записи для представленного ключа. При наличии свойства default_action оно должно указываться после свойства action. Оно может быть объявлено как константа, что препятствует динамической замене действия плоскостью управления. Действие, принятое по умолчанию, должно быть одним из указанных в списке actions. В частности, выражения, переданные как параметры in, out или inout должны быть синтаксически идентичны выражениям, использованным в одном из элементов списка действий.

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

const default_action = Rewrite_smac(48w0xAA_BB_CC_DD_EE_FF);

Отметим, что заданное действие по умолчанию должно предоставлять аргументы для привязанных плоскостью управления параметров (параметры без направления), поскольку принятое по умолчанию действие синтезируется во время компиляции. Выражения, представленные как аргументы для параметров с направлениям (in, inout, out) оцениваются при вызове действия, а выражения для параметров без аргументов — во время компиляции.

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

default_action = a(5); // корректно, нет параметров плоскости управления
// default_action = a(z); -- некорректно, параметр x для a уже привязан к значению 5
default_action = b(z,8w8); // корректно, параметр data для b привязан к 8w8
// default_action = b(z); -- некорректно, параметр data для b не привязан
// default_action = b(x, 3); -- некорректно, параметр x для b привязан к x вместо z

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

13.2.1.4. Записи

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

tableProperty
	: const ENTRIES '=' '{' entriesLlist '}' /* неизменные записи */

entriesList
	: entry
	| entriesList entry
	;

entry
	: keysetExpression ':' actionRef optAnnotations ';'
	;

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

Компонент записи keysetExpression является кортежем, который должен обеспечивать поле для каждого ключа в таблице (13.2.1. Свойства таблицы). Тип ключа таблицы должен соответствовать типу элемента в наборе. Компонент actionRef должен быть действием, которое присутствует в списке действий таблицы со всеми привязанными аргументами.

Если API среды выполнения требует приоритета для записей таблицы (например, при использовании P4 Runtime API таблицы хотя бы с одним троичным полем ключа поиска), записи сопоставляются в порядке указания в программе с остановкой на первой совпадающей записи. Архитектуре следует определять значимость порядка записей (если он имеется) для других типов таблиц.

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

Для иллюстрации рассмотрим приведенный ниже пример.

header hdr {
	bit<8>	e;
	bit<16> t;
	bit<8>	l;
	bit<8>	r;
	bit<1>	v;
}

struct Header_t {
	hdr h;
}

struct Meta_t {}

control ingress(inout Header_t h, inout Meta_t m,
			inout standard_metadata_t standard_meta) {
	action a() { standard_meta.egress_spec = 0; }
	action a_with_control_params(bit<9> x) { standard_meta.egress_spec = x; }

	table t_exact_ternary {
		key = {
			h.h.e : exact;
			h.h.t : ternary;
		}
		actions = {
			a;
			a_with_control_params;
		}
		default_action = a;
		const entries = {
			(0x01, 0x1111 &&& 0xF) : a_with_control_params(1);
			(0x02, 0x1181) : a_with_control_params(2);
			(0x03, 0x1111 &&& 0xF000) : a_with_control_params(3);
			(0x04, 0x1211 &&& 0x02F0) : a_with_control_params(4);
			(0x04, 0x1311 &&& 0x02F0) : a_with_control_params(5);
			(0x06, _) : a_with_control_params(6);
			_	: a;
		}
	}
}

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

13.2.1.5. Размер

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

Если у таблицы имеется значение размера N, компилятору рекомендуется выбрать реализацию плоскости данных, способную сохранять в таблице N записей. Это не гарантирует вставку в таблицу N произвольных записей и означает лишь возможность размещения в таблице некого набора из N записей. Например, попытка поместить в таблицу некоторую комбинацию из N записей может привести к отказу по причине того, что компилятор выбрал хэш-таблицу с гарантированным временем поиска O(1).

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

13.2.1.6. Дополнительные свойства

Объявление таблицы определяет важные интерфейсы плоскостей управления и данных — ключи и действия. Однако лучший способ реализации таблицы на деле может зависеть от природы записей, создаваемых в процессе работы (например, таблица может быть плотной или редкой, может быть реализована как хэш-таблица, ассоциативная память, дерево и т. п.). Кроме того, архитектура может поддерживать дополнительные свойства, семантика которых выходит за рамки данной спецификации. Например, в архитектуре со статическим выделением ресурсов таблиц может потребоваться задание в программе свойства size, которое компилятор back-end может использовать для выделения ресурсов хранения. Однако такие зависимые от архитектуры свойства не могут менять семантику поиска в таблицах, который всегда находит нужное действие или отсутствие такового. Можно лишь изменить интерпретацию результата поиска в плоскости данных. Это ограничение нужно для того, чтобы обеспечить возможность понять поведение таблиц во время компиляции.

В качестве другого примера свойство реализации можно использовать для передачи дополнительной информации компилятору back-end. Значение этого свойства может быть экземпляром внешнего блока, выбранного из подходящей библиотеки. Например, базовая функциональность конструкции action_profile в таблице P414 может быть реализована, как показано ниже.

extern ActionProfile {
	ActionProfile(bit<32> size); // число предполагаемых разных действий
}
table t {
	key = { /* тело опущено */ }
	size = 1024;
	implementation = ActionProfile(32);	// вызов конструктора
}

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

13.2.2. Вызов блока СД

Таблицу можно вызвать с помощью метода apply. Вызов этого метода для экземпляра таблицы возвращает значение типа struct с двумя полями. Эта структура создается компилятором авоматически. Для каждой таблицы T компилятор синтезирует enum и struct, как показано ниже.

enum action_list(T) {
	// одно поле для каждого действия из списка action в таблице T
}
struct apply_result(T) {
	bool hit;
	action_list(T) action_run;
}

Оценка метода apply устанавливает в поле hit значение true, а в miss — false, если в таблице найдено совпадение. В противном случае устанавливается hit = false и miss = true. Эти биты могут применяться в потоке управления вызвавшего таблицу блока управления.

if (ipv4_match.apply().hit) {
	// найдено совпадение (hit)
} else {
	// совпадения не найдено (miss)
}
if (ipv4_host.apply().miss) {
	ipv4_lpm.apply(); // поиск маршрута при отсутствии записи в таблице host
}

Поле action_run показывает тип выполняемого действия (независимо от hit или miss) и может использоваться в операторе switch, как показано ниже.

switch (dmac.apply().action_run) {
	Drop_action: { return; }
}

13.2.3. Семантика выполнения блока СД

Семантика оператора вызова таблицы показана ниже

m.apply();

и может быть представлена показанным ниже псевдокодом (см. рисунок 11).

apply_result(m) m.apply() {
	apply_result(m) result;
	var lookupKey = m.buildKey(m.key); // использование блока ключей
	action RA = m.table.lookup(lookupKey);
	if (RA == null) {	// нет в таблице поиска (miss)
		result.hit = false;
		RA = m.default_action;	// импользуется принятое по умолчанию действие
	} else {
		result.hit = true;
	}
	result.action_run = action_type(RA);
	evaluate_and_copy_in_RA_args(RA);
	execute(RA);
	copy_out_RA_args(RA);
	return result;
}

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

bit<8> f1 (in bit<8> a, inout bit<8> b) {
	b = a + 5;
	return a >> 1;
}
bit<8> x;
bit<8> y;
table t1 {
	key = {
		y & 0x7	: exact @name("masked_y");
		f1(x, y)	: exact @name("f1");
		y		: exact;
	}
	// ... здесь определяются остальные свойства таблицы, на связанные с примером
}
apply {
	// здесь присваиваются значения x и y, на связанные с примером
	t1.apply();
}

Это эквивалентно поведению другого определения таблицы и вызову apply.

// такие же определения f1, x, y как в предыдущем примере
bit<8> tmp_1;
bit<8> tmp_2;
bit<8> tmp_3;
table t1 {
	key = {
		tmp_1 : exact @name("masked_y");
		tmp_2 : exact @name("f1");
		tmp_3 : exact @name("y");
	}
	// ... здесь определяются остальные свойства таблицы, на связанные с примером
}
apply {
	// здесь присваиваются значения x и y, на связанные с примером
	tmp_1 = y & 0x7;
	tmp_2 = f1(x, y);
	tmp_3 = y;
	t1.apply();
}

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

13.3. Абстрактная машина конвейера СД

Можно описать вычислительную модель конвейера СД, воплощенного в блоке управления — тело блока выполняется аналогично традиционным императивным программам:

  • в среде выполнения операторы блока применяются в порядке их следования;

  • выполнение оператора return незамедлительно прерывает исполнение текущего блока и возвращает управления в точку вызова;

  • выполнение оператора exit незамедлительно прерывает исполнение текущего блока и всех блоков, в которых он содержится (откуда вызван);

  • использование таблицы выполняет соответствующий блок СД, как описано выше.

13.4. Вызов элемента управления

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

control Callee( inout IPv4 ipv4) { /* тело опущено */ }
control Caller(inout Headers h) {
	Callee() instance;	// экземпляр вызываемого блока
	apply {
		instance.apply(h.ipv4);	// вызов блока управления
	}
}

14. Параметризация

Для поддержки библиотек полезных компонентов P4 анализаторы и блоки управления можно параметризовать с помощью параметров конструктора. Рассмотрим синтаксис объявления конструктора

parserDeclaration
	: parserTypeDeclaration optConstructorParameters
		'{' parserLocalElements parserStates '}'
	;

optConstructorParameters
	: /* пусто */
	| '(' parameterList ')'
	;

Из этого правила можно вывести возможность наличия у конструктора двух наборов параметров:

  • параметры среды выполнения (parameterList);

  • необязательные параметры конструкутора (optConstructorParameters).

Параметры конструктора должны быть ненаправленными (не могут быть in, out, inout) и при создании экземпляра анализатора должна быть возможность полной оценки выражений, представленных для этих параметров, во время компиляции. Рассмотрим пример

parser GenericParser(packet_in b, out Packet_header p)
			(bool udpSupport) {	// параметры конструктора
	state start {
		b.extract(p.ethernet);
		transition select(p.ethernet.etherType) {
			16w0x0800: ipv4;
		}
	}
	state ipv4 {
		b.extract(p.ipv4);
		transition select(p.ipv4.protocol) {
			6: tcp;
			17: tryudp;
		}
	}
	state tryudp {
		transition select(udpSupport) {
			false: accept;
			true : udp;
		}
	}
	state udp {
		// тело опущено
	}
}

При создании GenericParser нужно представить значение для параметра udpSupport, как в примере ниже.

// topParser - это GenericParser, где udpSupport = false
GenericParser(false) topParser;

14.1. Прямой вызов типа

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

control Callee(/* параметры опущены */) { /* тело опущено */ }
control Caller(/* параметры опущены */)(/* параметры опущены */) {
	apply {
		Callee.apply(/* аргументы опущены */); // callee считается экземпляром
	}
}

Определение Caller эквивалентно приведенному ниже.

control Caller(/* параметры опущены */)(/* параметры опущены */) {
	@name("Callee") Callee() Callee_inst; // локальный экземпляр Callee
	apply {
		Callee_inst.apply(/* аргументы опущены */);	// применение Callee_inst
	}
}

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

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

  • В одной области действия прямые вызовы типа приводят к созданию своего локального экземпляра для каждого вызова, однако однотипные экземпляры будут иметь одно глобальное имя через аннотацию @name (17.3.2. Аннотации, управляющие именами). Если тип содержит управляемые элементы, неоднократные непосредственные вызовы в одной области действия недопустимы, поскольку будут создаваться несколько экземпляров управляемых элементов с одним именем.

15. Сборка пакета

Сборка пакетов (deparsing) в каком-то смысле обратна их анализу. P4 не поддерживает отдельного языка для сборки пакетов и она выполняется в блоках управления, имеющих по меньшей мере один параметр packet_out. Приведенный ниже фрагмент кода записывает поочередно заголовки Ethernet и IPv4 в packet_out.

control TopDeparser(inout Parsed_packet p, packet_out b) {
	apply {
		b.emit(p.ethernet);
		b.emit(p.ip);
	}
}

Выдача заголовка добавляет header к packet_out, если этот заголовок действителен. Выдача стека заголовков будет добавлять все элементы стека заголовков в порядке роста индексов.

15.1. Вставка данных в пакет

Тип packet_out определен в основной библиотеке P4 и это определение приведено ниже. Тип обеспечивает метод добавления данных в выходной пакет, называемый emit:

extern packet_out {
	void emit<T>(in T data);
}

Метод emit поддерживает добавления данных в заголовок, стек или объединение заголовков для выходного пакета.

  • При использовании с заголовком emit добавляет данные в заголовок пакета, если этот заголовок действителен, и ничего не делает в противном случае (no-op).

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

  • При использовании со структурой или объединением заголовков emit рекурсивно вызывается для каждого поля. Отметим, что в struct не допускаются поля типа error и enum, поскольку они не сериализуются.

Недопустим вызов emit для выражений базового типа, enum или error.

Вызов emit можно описать приведенным ниже псевдокодом.

packet_out {
	byte[] data;
	unsigned lengthInBits;
	void initializeForWriting() {
		this.data.clear();
		this.lengthInBits = 0;
	}
	/// Добавляются данные в пакет. T может быть заголовком, стеком или
	/// объединением заголовков и структурой из таких типов.
	void emit<T>(T data) {
		if (isHeader(T))
			if (data.valid$) {
				this.data.append(data);
				this.lengthInBits += data.lengthInBits;
			}
		else if (isHeaderStack(T))
			for (e : data)
				emit(e);
		else if (isHeaderUnion(T) || isStruct(T))
			for (f : data.fields$)
				emit(e.f)
		// Другие типы T недействительны
	}
}

Здесь применяются специальные идентификаторы valid$ для скрытого бита validity в заголовках и fields$ для списка полей struct или объединения заголовков. Применяется также стандартная нотация для итераций по элементам стека (e : data) и списку полей объединений заголовков или struct (f : data.fields$). Для struct итерации выполняются в порядке указания полей при определении типа.

16. Описание архитектуры

Описание архитектуры должно предоставляться производителем платформы в форме исходного кода библиотеки P4, который содержит по меньшей мере одно объявление пакета. Экземпляр этого пакета пользователь должен создать для своей программы. Примером может служить описание VSS в параграфе 5.1. Архитектура VSS.

Файл описания архитектуры может определять типы данных, константы, реализации вспомогательных программ (package) и ошибки. Он должен объявлять типы всех программируемых блоков, которые могут появляться на целевой платформе (анализаторы и блоки управления). Программируемые блоки могут группироваться в пакеты (package), которые могут быть вложенными.

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

16.1. Пример описания архитектуры

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

parser Parser<IH>(packet_in b, out IH parsedHeaders);
// входной конвейер СД
control IPipe<T, IH, OH>(in IH inputHeaders,
				in InControl inCtrl,
				out OH outputHeaders,
				out T toEgress,
				out OutControl outCtrl);
// выходной конвейер СД
control EPipe<T, IH, OH>(in IH inputHeaders,
				in InControl inCtrl,
				in T fromIngress,
				out OH outputHeaders,
				out OutControl outCtrl);
control Deparser<OH>(in OH outputHeaders, packet_out b);
package Ingress<T, IH, OH>(Parser<IH> p,
				IPipe<T, IH, OH> map,
				Deparser<OH> d);
package Egress<T, IH, OH>(Parser<IH> p,
				EPipe<T, IH, OH> map,
				Deparser<OH> d);
package Switch<T>(Ingress<T, _, _> ingress, Egress<T, _, _> egress);

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

  • Рисунок 12. Фрагмент примера коммутатора.

    Коммутатор содержит два отдельных пакета Ingress и Egress.

  • Блоки Parser, IPipe, Deparser в пакете Ingress соединены в цепочку. Кроме того, блок Ingress.IPipe имеет ввод типа Ingress.IH, который является выводом Ingress.Parser.

  • Аналогично пакет Egress включает блоки Parser, EPipe, Deparser.

  • Ingress.IPipe соединен с Egress.EPipe, поскольку первый дает на выход значение типа T, которое служит вводом для второго. Отметим, что экземпляры типа T создаются также в пакете Switch. Напротив, входной (Ingress) тип IH и выходной (Egress) тип IH могут различаться. Чтобы они совпадали, можно вместо объявления IH и OH на уровне коммутатора задать

    package Switch<T,IH,OH>(Ingress<T, IH, OH> ingress, Egress<T, IH, OH> egress).

Эта архитектура моделирует коммутатор, содержащий два разных канала между входным и выходным конвейером.

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

  • Канал опосредованной передачи с использованием анализатора с сериализацией данных в пакет и обратно.

16.2. Пример программы для архитектуры

Для работы на определенной архитектуре программа P4 должна создать экземпляр пакета верхнего уровня, передавая значения для всех его аргументов и создавая переменную с именем main в пространстве имен верхнего уровня. Типы аргументов должны соответствовать типам параметров после подходящей подстановки типов переменных. Подстановка типа может быть выражена напрямую с использованием специализации типа или выведена компилятором с использованием алгоритма унификации, подобного Hindley-Milner. Например, с объявлениями типов

parser Prs<T>(packet_in b, out T result);
control Pipe<T>(in T data);
package Switch<T>(Prs<T> p, Pipe<T> map);

и следующими объявлениями

parser P(packet_in b, out bit<32> index) { /* тело опущено */ }
control Pipe1(in bit<32> data) { /* тело опущено */ }
control Pipe2(in bit<8> data) { /* тело опущено */ }

Ниже приведено действительное объявление для целевой платформы верхнего уровня

Switch(P(), Pipe1()) main;

Следующее определение недействительно

Switch(P(), Pipe2()) main;

поскольку анализатор P требует для T тип bit<32>, а Pipe2 требует от T тип bit<8>.

Пользователь может явно задать значения переменных типа (иначе компилятор выведет их

Switch<bit<32>>(P(), Pipe1()) main;

16.3. Модель фильтра пакетов

Для демонстрации универсальности языка описания архитектуры P4 рассмотрим пример фильтрации пакетов, где решения принимаются исключительно по результатам анализатора P4, как показано на рисунке 13.


Рисунок 13. Модель фильтра пакетов.

Эту модель можно применить для фильтрации пакетов в ядре Linux. Например, можно заменить язык tcpdump более мощным языком P4, что позволит поддерживать новые протоколы с обеспечением полной «безопасности типов» при обработке пакетов. Для такой платформы компилятор P4 может генерировать программу eBPF (Extended Berkeley Packet Filter), которая инжектируется утилитой tcpdump в ядро Linux и выполняется EBPF kernel JIT.

Для цели в виде ядра Linux и архитектурной модели фильтра пакетов можно объявить

parser Parser<H>(packet_in packet, out H headers);
control Filter<H>(inout H headers, out bool accept);

package Program<H>(Parser<H> p, Filter<H> f);

17. Абстрактная машина P4 — оценка

Оценка программы P4 выполняется в два этапа:

  • статическая оценка происходит во время компиляции программы P4 путем анализа и создания экземпляров всех блоков с состоянием;

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

17.1. Известные при компиляции значения

  • Целочисленные, логические и строковые литералы.

  • Идентификаторы из объявления error, enum, match_kind.

  • Идентификатор default.

  • Поле size значения с типом стека заголовков.

  • Идентификатор _ при использовании в выражениях select.

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

  • Списки, в которых все компоненты имеют известные при компиляции значения.

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

  • Экземпляры, создаваемые объявлениями (10.3. Создание экземпляров) и вызовами конструкторов.

  • Выражения +, -, *, / , %, cast, !, &, |, &&, ||, << , >> , ~ , >, <, ==, !=, <=, >=, ++, [:], где все операнды известны при компиляции.

  • Идентификаторы, объявленные как константы с использованием ключевого слова const.

  • Выражения в форме e.minSizeInBits() и e.minSizeInBytes().

17.2. Оценка при компиляции

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

  • Все объявления (например, анализаторы, элементы управления, типы, константы) оценивают сами себя.

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

  • Вызовы конструкторов оцениваю объекты с состоянием соответствующего типа. Для этого все аргументы конструктора оцениваются рекурсивно и привязываются к параметрам конструктора. Аргументы конструктора должны быть известны при компиляции. Порядок оценки аргументов конструктора не должен играть роли, поскольку он не влияет на результат.

  • Экземпляры оценивают именованные объекты с состоянием.

  • Экземпляр анализатора или элемента управления рекурсивно оценивает все экземпляры с состоянием, объявленные в блоке.

  • Результатом оценки программы является значение переменной верхнего уровня main.

Отметим, что все значения с состоянием оцениваются во время компиляции.

В качестве примера рассмотрим фрагмент программы, приведенный ниже.

// объявления архитектуры
parser P(/* параметры опущены */);
control C(/* параметры опущены */);
control D(/* параметры опущены */);

package Switch(P prs, C ctrl, D dep);
extern Checksum16 { /* тело опущено */}

// пользовательский код
Checksum16() ck16; // экземпляр блока контрольных сумм
parser TopParser(/* параметры опущены */)(Checksum16 unit) { /* тело опущено */}
control Pipe(/* параметры опущены */) { /* body omitted */}
control TopDeparser(/* параметры опущены */)(Checksum16 unit) { /* тело опущено */}

Switch(TopParser(ck16), Pipe(), TopDeparser(ck16)) main;

Оценка этой программы происходит в описанном ниже порядке.

  1. Объявления P, C, D, Switch, Checksum16 оценивают себя сами.

  2. Экземпляр Checksum16() ck16 оценивается и создает объект ck16 типа Checksum16.

  3. Объявления TopParser, Pipe, TopDeparser оценивают себя сами.

  4. Выполняется оценка экземпляра переменной :

    1. рекурсивно оцениваются аргументы конструктора;

    2. вызывается конструктор TopParser(ck16)

    3. аргументы оцениваются рекурсивно, оценивается объект ck16;

    4. оценивается сам конструктор, что ведет к созданию объекта типа TopParser;

    5. аналогично Pipe() и TopDeparser(ck16) оцениваются как вызовы конструктора;

    6. оцениваются все аргументы конструктора пакета Switch (экзепляры TopParser, Pipe, TopDeparser) и их сигнатуры сопоставляются с определением Switch;

    7. оценивается конструктор Switch, результатом чего является экземпляр пакет Switch (prs типа TopParser является первым параметром, ctrl типа Pipe — вторым, dep типа TopDeparser — третьим).

  5. Результатом оценки программы является значение переменной main — экземпляра пакета Switch.

 
Рисунок 14. Результат оценки.

На рисунке 14 показан результат оценки в графической форме, представляющий собой граф экземпляров. Имеется 1 экземпляр Checksum16 (ck16), совместно используемый TopParser и TopDeparser (конкретная архитектура может потребовать использования разных блоков контрольной суммы).

17.3. Имена элементов управления

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

17.3.1. Вычисление имен элементов управления

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

17.3.1.1. Таблицы

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

control c(/* параметры опущены */)() {
	table t { /* тело опущено */ }
}

создаст таблицу с локальным именем t.

17.3.1.2. Ключи

Синтаксически ключи таблицы являются выражениями. Для простых выражений локальное имя может создаваться из самого выражения. Ниже приведен пример таблицы t, ключи которой названы data.f1 и hdrs[3].f2.

table t {
	keys = {
		data.f1 : exact;
		hdrs[3].f2 : exact;
	}
	actions = { /* тело опущено */ }
}

Перечисленные в таблице виды выражений имеют локальные имена, выведенные из их синтаксических имен.

Выражение

Пример

Имя

Метод isValid()

h.isValid()

«h.isValid()»

Доступ к массиву

header_stack[1]

«header_stack[1]»

Константа

1

«1»

Проекция поля

data.f1

«data.f1»

Нарезка

F1[3:0]

«f1[3:0]»

Все прочие выражения должны аннотироваться с использованием @name (18.3.3. Аннотации API плоскости управления), как показано ниже.

table t {
	keys = {
		data.f1 + 1 : exact @name("f1_mask");
	}
	actions = { /* тело опущено */ }
}

Здесь аннотация @name(«f1_mask») назначает ключу локальное имя «f1_mask».

17.3.1.3. Действия

Для конструкции action локальным именем действия является синтаксическое имя action. Например,

control c(/* параметры опущены */)() {
	action a(...) { /* тело опущено */ }
}

создает локальное имя a.

17.3.1.4. Экземпляры

Локальные имена экземпляров extern, parser и control выводятся на основе использования экземпляра. Если экземпляр привязан к имени, оно становится локальным именам для плоскости управления. Например, при объявлении control C

control C(/* параметры опущены */)() { /* тело опущено */ }

и создании экземпляра

C() c_inst;

локальным именем будет c_inst. Если экземпляр создается в качестве аргумента, его локальным именем будет имя формального параметра, к которому экземпляр привязан. Например при объявлении extern E и control C

extern E { /* тело опущено */ }
control C( /* параметры опущены */ )(E e_in) { /* тело опущено */ }

и создании экземпляра

C(E()) c_inst;

локальным именем экземпляра extern будет e_in.

Если создаваемая конструкция передается как аргумент пакету (package), имя экземпляра выводится из представленного пользователем объявления, когда это возможно. В приведенном ниже примере локальным именем MyC будет c, а локальным именем extern — e2, а не e1.

extern E { /* тело опущено */ }
control ArchC(E e1);
package Arch(ArchC c);

control MyC(E e2)() { /* тело опущено */ }
Arch(MyC()) main;

Отметим, что в этом примере архитектура будет представлять экземпляр extern при передаче экземпляра MyC пакету Arch. Полным именем этого экземпляра будет main.c.e2.

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

control Callee() {
	table t { /* тело опущено */ }
	apply { t.apply(); }
}
control Caller() {
	Callee() c1;
	Callee() c2;
	apply {
		c1.apply();
		c2.apply();
	}
}
control Simple();
package Top(Simple s);
Top(Caller()) main;

 
Рисунок 15. Оценка программы с несколькими экземплярами компонентов.

Оценка этой программы при компиляции создает структуру, показанную на рисунке 15. Отметим наличие двух экземпляров таблицы t, которые (оба) должны быть раскрыты плоскости управления. Для именования объектов в этой иерархии используется компонент пути имен, содержащих экземпляры. В данном случае две таблицы будут называться s.c1.t и s.c2.t, где s — имя аргумента для создания экземпляра пакета, которое выводится из имени соответствующего формального параметра.

17.3.2. Аннотации, управляющие именами

Аннотации, относящиеся к плоскости управления (18.3.3. Аннотации API плоскости управления), могут менять видимые плоскости управления имена.

  • Аннотация @hidden скрывает управляемый элемент от плоскости управления. Это единственный случай, когда управляемому объекту не требуется уникальное полное имя.

  • Можно использовать аннотацию @для смены локального имени управляемого объекта.

Программы, выдающие одно полное имя для двух разных управляемых элементов, недопустимы.

17.3.3. Рекомендации

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

control c( /* параметры опущены */)() {
	action a ( /* параметры опущены */ ) { /* тело опущено */ }
	table t {
		keys = { /* тело опущено */ }
		actions = { a; } 
	}
}
c() c_inst;

Программы плоскости управления могут указывать действие c_inst.a как a при вставке правил в таблицу c_inst.t, поскольку это ясно из определения таблица, к которой относится действие.

Не все однозначные сокращения можно рекомендовать. Рассмотрим первый пример из параграфа 17.3. Имена элементов управления. Можно подумать о ссылке на s.c1 как c1, поскольку в программе нет другого объекта c1. Однако это сделает программу «хрупкой», поскольку ее новые версии не смогут создавать экземпляр с именем c1 или включать библиотеки P4, где имеется объект с таким именем.

17.4. Динамическая оценка

Динамическая оценка программу P4 организуется архитектурной моделью. Каждая модель должна задавать порядок и условия динамического выполнения различных компонентов программы P4. Например, в VSS из раздела 5.1. Архитектура VSS поток выполнения имеет вид Parser->Pipe->Deparser. При вызове блока исполнения P4 он работает до завершения (прерывания) в соответствии с описанной здесь семантикой.

17.4.1. Модель одновременной работы

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

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

Внешние блоки, экземпляры которых создаются программой P4, являются глобальными и используются всеми потоками. Если внешние блоки участвуют в доступе к состоянию (счетчики, регистры), т. е. к методам чтения и записи состояний, эти операции являются «состязательными». P4 требует атомарного (неделимого) выполнения вызовов методов и экземпляров extern. Для атомарного выполнения больших блоков кода в P4 применяется аннотация @atomic для блока операторов, состояния анализатора, блока управления или анализатора целиком. Рассмотрим пример.

extern Register { /* тело опущено */ }
control Ingress() {
	Register() r;
	table flowlet { /* чтение состояния r в действии (action) */ }
	table new_flowlet { /* запись состояния r в действии (action) */ }
	apply {
		@atomic {
			flowlet.apply();
			if (ingress_metadata.flow_ipg > FLOWLET_INACTIVE_TIMEOUT)
				new_flowlet.apply();
}}}

Программа обращается к внешнему объекту r типа Register в действиях из таблиц flowlet (чтение) и new_flowlet (запись). Без аннотации @atomic эти операции не будут выполняться атомарно и для второго пакета состояние r может быть считано до того, как первый изменит его.

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

18. Аннотации

Аннотации похожи на атрибуты C# и аннотации Java. Это просто механизм ограниченного расширения языка P4 без изменения грамматики. В какой-то степени аннотации включают #pragma из языка C. Аннотации присоединяются к типам, полям, переменным и т. п. с использованием синтаксиса @ (как показано явно в грамматике P4). Неструктурированные аннотации или просто аннотации могут не иметь тела, для структурированных тело обязательно и должно содержать хотя бы одну пару скобок [].

optAnnotations
	: /* пусто */
	| annotations
	;
annotations
	: annotation
	| annotations annotation
	;
annotation
	: '@' name
	| '@' name '(' annotationBody ')'
	| '@' name '[' structuredAnnotationBody ']'
	;

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

Действительные аннотации

@my_anno(1) table T { /* тело опущено */ }
@my_anno[2] table U { /* тело опущено */ } // разные области с предыдущей my_anno

Недействительные аннотации

@my_anno(1)
@my_anno[2] table U { /* тело опущено */ } // ошибка — изменен тип anno для элемента

Для данного элемента может задаваться множество неструктурированных аннотаций с одним именем — они аккумулируются и все будут связаны с этим элементом. Структурированная аннотация с данным именем для элемента может быть лишь одна и наличие нескольких аннотаций создаст ошибку.

Действительные аннотации

@my_anno(1)
@my_anno(2) table U { /* тело опущено */ }	// неструктурированные аннотации акумулируются

Недействительные аннотации

@my_anno[1]
@my_anno[2] table U { /* тело опущено */ } // ошибка — та же структурированная аннотация

18.1. Тело неструктурированной аннотации

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

annotationBody
	: /* пусто */
	| annotationBody '(' annotationBody ')'
	| annotationBody annotationToken

Неструктурированные аннотации могут иметь ту или иную структуру в своем теле, не определяемую языком P4. Например, спецификация P4Runtime определяет аннотацию @pkginfo, предполагающую пару ключ-значение.

18.2. Тело структурированных аннотаций

В отличие от неструктурированных аннотаций структурированные используют скобки […] и формат их ограничен. Обычно такие аннотации служат для объявления пользовательских метаданных, состоящих из списков выражений или списков пар ключ-значение (но не обоих). Элемент expressionList может быть пустым или содержать список разделенных запятыми выражений. Элемент kvList включает одну или несколько пар kvPair, каждая из которых включает ключ и значение. Синтаксис выражения описан ниже (Приложение H. Грамматика P4 ).

Все выражения в structuredAnnotationBody должны иметь известные при компиляции значения — литералы или выражения, которые должны быть вычислены при компиляции, с типом результата string, int с неограниченной разрядностью или boolean. Структурированные выражения (например, выражения с expressionList, kvList и т. п.) не допускаются. Отметим, что информация P4Runtime (P4Info) может предусматривать дополнительные ограничения, например, целочисленные выражения могут быть ограничены 64-битовыми значениями. Не допускается дублирование ключей в kvList структурированной аннотации.

structuredAnnotationBody
	: expressionList
	| kvList
	;
...
expressionList
	: /* пусто */
	| expression
	| expressionList ',' expression
	;
...
kvList
	: kvPair
	| kvList ',' kvPair
	;
kvPair
: name '=' expression
;

18.2.1. Примеры структурированных аннотаций

Пустой список выражений имеет пустую аннотацию

@Empty[]
table t { /* тело опущено */ }

Смешанный список выражения будет иметь аннотацию вида

[1,"hello",true, false, 11]
#define TEXT_CONST "hello"
#define NUM_CONST 6
@MixedExprList[1,TEXT_CONST,true,1==2,5+NUM_CONST]
table t { /* тело опущено */ }

Список строк kvList

@Labels[short="Short Label", hover="My Longer Table Label to appear in hover-help"]
table t { /* тело опущено */ }

Список смешанных выражений kvList имеет аннотацию

[label="text", my_bool=true, int_val=6]
@MixedKV[label="text", my_bool=true, int_val=2*3]
table t { /* тело опущено */ }

Список смешанных kvPair и expressionList будет недействительным, поскольку в нем смешаны kvPair и выражения

@IllegalMixing[key=4, 5] // недопустимое смешивание
table t { /* тело опущено */ }

Недействительное дублирование ключа

@DupKey[k1=4,k1=5] // недопустимое дублирование ключа
table t { /* тело опущено */ }

Недопустимое дублирование структурированных аннотаций

@DupAnno[k1=4]
@DupAnno[k2=5] // недопустимое дублирование имени
table t { /* тело опущено */ }

Недопустимое использование структурированной и неструктурированной аннотации

@MixAnno("Anything")
@MixAnno[k2=5] // недопустимое использование обоих типов аннотаций
table t { /* тело опущено */ }

18.3. Предопределенные аннотации

Имена аннотаций, начинающиеся со строчной буквы зарезервированы для стандартной библиотеки и архитектуры. Этот документ определяет «стандартные» аннотации в Приложении C. Предполагается, что этот список будет расти. Для архитектуры рекомендуется определять аннотации, начинающиеся с префикса производителя, например, организация X может использовать для аннотаций имена вида @X_annotation

18.3.1. Аннотации необязательных параметров

Параметр для пакета, внешнего метода, функции или объекта аннотируется с помощью @optional для указания того, что параметр не требует соответствующего аргумента. Значение параметра без аргумента зависит от платформы.

18.3.2. Аннотации списка действий таблицы

Для предоставления компилятору и плоскости управления дополнительной информации о действиях таблицы используются две аннотации, не имеющие тела:

  • @tableonly указывает, что действие может присутствовать лишь в таблице и не применяется по умолчанию;

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

table t {
	actions = {
		a,		// может применяться везде
		@tableonly b,	// может применяться лишь в таблице
		@defaultonly c, 	// может использоваться лишь по умолчанию
	}
	/* тело опущено */
}

18.3.3. Аннотации API плоскости управления

Аннотация @name указывает компилятору использовать другое локальное имя при генерации внешних API для манипуляций с объектом из плоскости управления. Телом аннотации является строковый литерал. В приведенном примере таблица имеет полное имя c_inst.t1.

control c( /* параметры опущены */ )() {
	@name("t1") table t { /* тело опущено */ }
	apply { /* тело опущено */ }
}
c() c_inst;

Аннотация @hidden скрывает управляемый элемент (например, таблицу, ключ, действие или extern) от плоскости управления, удаляя по сути полное имя (17.3. Имена элементов управления). Аннотация не имеет тела.

18.3.3.1. Ограничения

Для каждого элемента можно применять не более одной аннотации @name или @hidden, а каждое имя плоскости управления должно указывать не более одного управляемого объекта. Это вызывает озабоченность при использовании абсолютной аннотации @name — если тип, содержащий аннотацию @name с абсолютным путем (начинается с .) создается неоднократно, это приведет к одному имени у нескольких управляемых элементов.

control noargs();
package top(noargs c1, noargs c2);
control c() {
	@name(".foo.bar") table t { /* тело опущено */ }
	apply { /* тело опущено */ }
}
top(c(), c()) main;

Без аннотации @name эта программа будет создавать два управляемых элемента с полными именами main.c1.t и main.c2.t. Однако аннотация @name(«.foo.bar») переименуют в обоих экземплярах таблицу t в foo.bar и имена двух управляемых элементов совпадут,что недопустимо.

18.3.4. Аннотации одновременных элементов управления

Аннотация @atomic (17.4.1. Модель одновременной работы) позволяет обеспечить неделимость блока операций.

18.3.5. Аннотации наборов значений

Аннотация @match (12.6. Выражения для выбора) служит для задания match_kind, отличного принятого по умолчанию, для точного значения поля value_set.

18.3.6. Аннотации внешних функций и методов

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

  • @pure описывает функцию, зависящую лишь от значений параметров и не оказывающую никакого влияния, кроме возврата значения и поведения copy-out для параметров out и inout. Между вызовами не записывается скрытых состояний и значение не зависит от скрытого состояния, которое могут менять другие вызовы. Примером является хэш-функция, которая рассчитывает детерминированную свертку своих аргументов и возвращаемое значение не зависит от доступных для записи плоскости управления состояний или значения вектора инициализации. Функция @pure, результат которой не используется, может быть исключена без каких-либо неблагоприятных последствий, а множество вызовов с одними аргументами можно объединить в один вызов (с учетом ограничений поведения copy-out для параметров out и inout). Порядок вызова функций @pure можно менять относительно других расчетов, которые не зависят от данных.

  • @noSideEffects слабее, чем @pure, и описывает функции, не меняющие скрытых состояний, но зависящие от таковых. Примером является хэш-функция, рассчитывающая детерминированную свертку аргументов с учетом некого внутреннего состояния, которое может быть изменено через API плоскости управления (например, вектор инициализации). Другим примером служит чтение одного элемента массива регистров объекта extern. Такая функция может быть исключена и можно изменить ее порядок по отношению к другим вызовам @noSideEffects и @pure (с учетом ограничений поведения copy-out для параметров out и inout), но не к вызовам других функций, которые могут воздействовать на данную.

18.3.7. Аннотация отмены

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

@deprecated("Please use the 'check' function instead")
extern Checker { /* тело опущено */ }

18.3.8. Отключение предупреждений

Аннотация noWarn имеет обязательный строковый аргумент, который указывает подавляемые предупреждения компилятора. Например @noWarn(«unused») будет предотвращать вывод предупреждений компилятора о неиспользуемых объявлениях.

18.4. Зависимые от платформы аннотации

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

  • ошибку при некорректном использовании аннотаций (например, отсутствие или некорректный тип параметра);

  • предупреждения при неизвестных аннотациях.

Приложение A. История выпусков

Версия

Дата

Изменения

1.0.0

17.05. 2017

Исходная версия.

1.1.0

26.11.2018

Добавлены функции верхнего уровня, необязательные и именованные параметры, представления enum, наборы значений анализатора, определения типов, арифметика с насыщением и структурированные аннотации. Исключена аннотация globalname, добавлено свойство таблицы size. Разъяснена семантика операций с недействительными заголовками, добавлены ограничения для аргументов вызова, изменен порядок выполнения побитовых операторов.

1.2.0

14.10.2019

Добавлена ошибка ParserInvalidArgument, порядок записей const, методы size для заголовков, 1-битовые значения со знаком, нарезки битов со знаком, пустые кортежи, аннтация @deprecated, аннотации в свободной форме, тип int для table.apply().miss, тип string.

1.2.1

11.06.2020

Добавлены выражения со значением struct, принятые по умолчанию значения, конкатенация, структурированные аннотации. Стандартизовано несколько новых аннотаций, обобщено правило типизации для масок, ограничено правило типизации для сдвига с оперантами неограниченного размера. Разъяснен порядок оценки для ключей таблиц, поведение copy-out behavior, семантика недействительных стеков заголовков, семантика инициализации. Исправлено несколько мелких проблем в грамматике.

A.1. Изменения в версии 1.2.1

  • Добавлены выражения со значением struct (8.12. Выражения со значением struct).

  • Добавлена поддержка принятых по умолчанию значений (7.3. Подразумеваемые значения).

  • Добавлена поддержка конкатенации строк (8.6.1. Конкатенация).

  • Добавлены аннотации key-value и со структурой списка (18. Аннотации).

  • Добавлены аннотации @pure и @noSideEffects (18.3.6. Аннотации внешних функций и методов).

  • Добавлены аннотации @noWarn (18.3.8. Отключение предупреждений).

  • Обобщена типизация масок для сериализации enum (18.3.3. Аннотации API плоскости управления).

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

  • Разъяснено поведение copy-out для return (11.4. Оператор возврата) и exit (11.5. Оператор выхода).

  • Разъяснена семантика недействительных стеков заголовков (8.17. Операции над стеком заголовков).

  • Разъяснена семантика инициализации (6.6. Выражения для левой части, 6.7. Соглашения о вызовах), в частности, для заголовков и локальных переменных.

  • Разъяснен порядок оценки ключей таблицы (13.2.3. Семантика выполнения блока СД).

  • Уточнена грамматика для анализа сдвига вправо (>>) для поддержки пустых операторов в анализаторе (12.4. Состояния анализатора) и исключения аннотаций для записей const (13.2.1.4. Записи).

A.2. Изменения в версии 1.2.0

  • Добавлено table.apply().miss (13.2.2. Вызов блока СД).

  • Добавлен тип string (7.1.5. Строки).

  • Добавлено неявное приведение для значений типа enum (8.3. Операции над типом enum).

  • Добавлены 1-битовые значения со знаком.

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

  • Ограничено местоположение метки default в операторах switch.

  • Разрешены пустые кортежи.

  • Добавлена аннотация @deprecated.

  • Смягчены требования к структуре тела аннотаций.

  • Исключена аннотация @pkginfo, перенесенная в спецификацию P4Runtime.

  • Добавлен тип int (7.1.6.5. Целые числа “бесконечной точности”).

  • Добавлена ошибка ParserInvalidArgument (12.8.2. Извлечение при переменном размере, 12.8.4. Пропуск битов).

  • Разъяснена значимость порядка элементов в записях const (13.2.1.4. Записи).

  • Добавлены методы расчета размера заголовков (8.16. Операции над заголовками).

A.3. Изменения в версии 1.1.0

  • Разрешено объявление функций на верхнем уровне программ P4 (9. Объявление функции).

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

  • Добавлены перечисляемые значения — enum (8.3. Операции над типом enum).

  • Добавлены наборы значений анализатора — value_set для программируемых плоскостью управление меток select (12.11. Набор значений анализатора).

  • Разрешено определять новые типы в программах (7.5. Создание новых типов).

  • Добавлена поддержка арифметики с насыщением для некоторых платформ (8.5. Операции над битовыми типами (целые числа без знака)).

  • Добавлены структурированные аннотации как списки пар ключ-значение (18. Аннотации).

  • Удалена аннотация globalname (17.3.2. Аннотации, управляющие именами).

  • Добавлено необязательное свойство таблицы size (13.2.1.5. Размер).

  • Разъяснена семантика операций с недействительными заголовками (8.16. Операции над заголовками).

  • Добавлены ограничения на типы значений аргументов при вызовах (Приложение F. Ограничения для вызовов при компиляции и работе).

  • Изменен порядок побитовых операторов (Приложение H. Грамматика P4 ) — &, | и ^ имеют более высокий приоритет, нежели <, >, <=, >=.

  • Добавлена поддержка задания размера типов bit и varbit с использованием выражений (7.1. Базовые типы).

Приложение B. Зарезервированные слова P4

Ниже приведен список зарезервированных (ключевых) слов P4. Некоторые слова являются зарезервированными лишь в определенном контексте (например, actions).

action

apply

bit

bool

const

control

default

else

enum

error

extern

exit

false

header

header_union

if

in

inout

int

match_kind

package

parser

out

return

select

state

string

struct

switch

table

transition

true

tuple

typedef

varbit

verify

void

Приложение C. Зарезервированные аннотации P4

Аннотация

Назначение

Параграф

atomic

Задает неделимое (атомарное) выполнение

17.4.1

defaultonly

Действие может использоваться лишь по умолчанию (default).

18.3.2

hidden

Скрывает управляемый объект от плоскости управления.

17.3.2

match

Задает поле match_kind в value_set.

18.3.5

name

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

17.3.2

optional

Указывает необязательный параметр.

18.3.1

tableonly

Действие не может использоваться по умолчанию (default).

18.3.2

deprecated

Указывает отмененную (устаревшую) конструкцию.

18.3.7

pure

«Чистая» функция.

18.3.6

noSideEffects

Функция без побочных эффектов.

18.3.6

noWarn

Отключает предупреждения компилятора (аргумент типа string)

18.3.8

Приложение D. Основная библиотека P4

Основная библиотека P4 содержит объявления, нужные большинству программ. Например, она включает определения внешних объектов packet_in и packet_out, применяемых анализаторами и сборщиками при работе с пакетом.

/// Стандартные коды ошибок. Пользователи могут добавлять свои коды.
error {
	NoError,		/// Нет ошибок.
	PacketTooShort,	/// В пакете недостаточно битов для извлечения.
	NoMatch,		/// Выражение select не имеет совпадений.
	StackOutOfBounds,	/// ссылка на недействительный элемент стека заголовков.
	HeaderTooShort,	/// Извлечение излишнего числа битов в поле varbit.
	ParserTimeout,	/// Превышено время работы анализатора.
	ParserInvalidArgument	/// Операция анализатора вызвана с неподдерживаемым
					/// реализацией значением.
}
extern packet_in {
	/// Чтение заголовка из пакета в заголовок фиксированного размера @hdr
	/// и перемещение указателя. Может вызывать ошибку PacketTooShort или
	/// StackOutOfBounds. @T - тип заголовка с фиксированным размером.
	void extract<T>(out T hdr);
	/// Чтение битов из пакета в заголовок переменного размера @variableSizeHeader
	/// и перемещение указателя. Заголовок @T должен содержать 1 поле varbit.
	/// Может вызывать ошибки PacketTooShort, StackOutOfBounds, HeaderTooShort.
	void extract<T>(out T variableSizeHeader,
		in bit<32> variableFieldSizeInBits);
	/// Чтерие битов из пакета без перемещения указателя. @returns содержит
	/// прочитанные биты T может быть произвольным фиксированным заголовком.
	T lookahead<T>();
	/// Перемещение указателя на заданное число битов.
	void advance(in bit<32> sizeInBits);
	/// @return - размер пакета в байтах. Метод поддерживается не всеми
	/// архитектурами.
	bit<32> length();
}
extern packet_out {
	/// запись @data в выходной пакет с пропуском недействительных заголовков
	/// и перемещением указателя. @T может быть заголовокм, стеком или
	/// объединением заголовков, а также struct с полями этих типов.
	void emit<T>(in T data);
}
action NoAction() {}
/// Стандартные типы сопоставления для полей ключей в таблице. Некоторые 
/// архитектуры могут поддерживать не все типы сопоставления. Архитектура
/// может задавать свои типы.
match_kind {
	exact,		/// Точное сопоставление.
	ternary,	/// Троичное сопоставление с использованием маски.
	lpm		/// Наибольший совпадающий префикс.
}

Приложение E. Контрольные суммы

В P416 нет встроенных конструкций для работы с контрольными суммами. Предполагается выполнение таких операций внешними объектами, обеспечиваемыми зависимыми от платформы библиотеками. Библиотеке стандартной архитектуры следует включать блоки работы с контрольными суммами. Например, можно предоставить блок инкрементного расчета контрольных сумм Checksum16 (5.2.4. Доступные внешние блоки) для 16-битовых контрольных сумм с дополнением до 1 с использованием внешнего объекта, как показано ниже.

extern Checksum16 {
	Checksum16();		// конструктор
	void clear();		// подготовка блока к расчетам
	void update<T>(in T data);	// добавление данных в контрольную сумму
	void remove<T>(in T data);	// исключение данных из контрольной суммы
	bit<16> get(); 	// расчет контрольной суммы для данных, добавленных после очистки
}

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

ck16.clear();		// подготовка блока контрольной суммы
ck16.update(h.ipv4);	// запись заголовка
verify(ck16.get() == 16w0, error.IPv4ChecksumError); // проверка значения 0

Расчет контрольной суммы IP можно выполнить в форме

h.ipv4.hdrChecksum = 16w0;
ck16.clear();
ck16.update(h.ipv4);
h.ipv4.hdrChecksum = ck16.get();

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

ck16.clear();
ck16.update(h.ipv4.hdrChecksum);	// исходная контрольная сумма
ck16.remove( { h.ipv4.ttl, h.ipv4.proto } );
h.ipv4.ttl = h.ipv4.ttl - 1;
ck16.update( { h.ipv4.ttl, h.ipv4.proto } );
h.ipv4.hdrChecksum = ck16.get();

Приложение F. Ограничения для вызовов при компиляции и работе

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

Объектами с состоянием в P416 являются пакеты (package), анализаторы, элементы управления, внешние объекты (extern), таблицы и наборы значений. Функции P416 также относятся к этой группе, даже если они зависят лишь от своих аргументов (pure). Все остальные типы здесь называются типами значений (value type).

Некоторые базовые принципы перечислены ниже.

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

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

  • Внешним элементам не разрешено вызывать анализаторы и элементы управления, поэтому нет смысла передавать им такие объекты.

  • Экземпляры таблиц всегда создаются напрямую во включающих таблицы элементах управления и не могут создаваться на верхнем уровне. Синтаксис задания параметров таблиц не определяется. Таблица предназначена для использования лишь в определившем ее элементе управления.

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

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

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

Может быть параметром конструктора для типа

Тип

package

parser

control

extern

package

да

нет

нет

нет

parser

да

да

нет

нет

control

да

нет

да

нет

extern

да

да

да

да

function

нет

нет

нет

нет

table

нет

нет

нет

нет

value-set

нет

нет

нет

нет

Типы значений

да

да

да

да

В следующей таблице показаны ограничения на создание экземпляров (10.3. Создание экземпляров) разных типов. Ответы «нет» в столбце означают, что нет создания экземпляров «внутри пакета» в P416. Можно явно вызвать конструктор и использовать экземпляры типов с состояниями при создании экземпляра пакета с учетом приведенных ниже ограничений. Для типов extern можно указать лишь интерфейс в P416, но не реализацию, поэтому экземпляры внутри extern не создаются. Можно объявить переменные и константы любого из типов значений внутри анализатора, элемента управления или функции (10.2. Переменные). Такое объявление отличается от создания экземпляра, поэтому с таблице указано «-». Переменные нельзя объявлять на верхнем уровне программы, а константы можно.

Экземпляр может создаваться в

Тип

Верхний уровень

package

parser

control

extern

function

package

да

нет

нет

нет

нет

нет

parser

нет

нет

да

нет

нет

нет

control

нет

нет

нет

да

нет

нет

extern

да

нет

да

да

нет

нет

function

да

нет

нет

нет

нет

нет

table

нет

нет

нет

да

нет

нет

value-set

да

нет

да

нет

нет

нет

Типы значений

В следующей таблице приведены ограничения для типов, которые могут передаваться в качестве параметров при работе другим элементам, способным принимать такие параметры (parser, control, extern, action, function).

Может быть параметром в среде выполнения для вызова

Тип

parser

control

method

action

function

package

нет

нет

нет

нет

нет

parser

нет

нет

нет

нет

нет

control

нет

нет

нет

нет

нет

extern

да

да

да

нет

нет

table

нет

нет

нет

нет

нет

value-set

нет

нет

нет

нет

нет

action

нет

нет

нет

нет

нет

function

нет

нет

нет

нет

нет

Типы значений

да

да

да

да

да

Вызовы метода extern могут возвращать лишь типы значений или не возвращать ничего (return void).

В следующей таблице показаны ограничения для вызовов, доступных из разных мест программы P4. Вызов анализатора, элемента управления или таблицы означает применение метода apply(), вызов value-set — использование в выражении select. Строка для extern указывает, откуда можно вызывать внешние методы. Одним из способов вызова extern с верхнего уровня анализатора или элемента управления является выражение инициализатора для объявленной переменной, например, bit<32> x = rand.get();.

Может вызываться при работе из указанного места программы P4

Тип

Состояние анализатора

Метод apply элемента управления

Верхний уровень анализатора или элемента управления

action

extern

function

package

parser

да

нет

нет

нет

нет

нет

control

нет

да

нет

нет

нет

нет

extern

да

да

да

да

нет

нет

table

нет

да

нет

нет

нет

нет

value-set

да

нет

нет

нет

нет

нет

action

нет

да

нет

да

нет

нет

function

да

да

нет

да

нет

да

Типы значений

Вызовы не допускают рекурсии ни напрямую, ни опосредованно (взаимная рекурсия). Методы extern не могут вызывать другие типы программных объектов P4 (6.7.1. Обоснование). Действия могут вызываться напрямую из блока apply элементов управления.

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

Приложение G. Нерешенные проблемы

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

G.1. Обобщенное поведение оператора switch

P416 включает операторы switch (11.7. Оператор выбора) и выражения select (12.6. Выражения для выбора). Они реально различаются в текущей версии языка. Оператор должен оцениваться в значение состояния. Предлагается обобщенный оператор switch, соответствующий принятым в большинстве языков программирования — условие со множеством вариантов, из которых выбирается первый подходящий.

switch(e1,/* параметры опущены */,en) {
	pat_1 : stmt1;
	/* тело опущено */
	pat_m : stmtm;
}

В примере проверяемое значение задано кортежем (e1,/* параметры опущены */,en), а варианты — выражениями, обозначающими наборы значений. Значение соответствует варианту (branch), если оно входит в набор, заданный выражением. В отличие от C и C++, здесь не применяется оператор break для предотвращения перехода к следующему варианту и такой переход возможен лишь при несоответствии значения текущей ветви (метке).

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

Обобщено также устройство обработки для таблиц совпадений и отсутствия (hit/miss) и действий в блоках управления, путем генерации неявных типов для действий и результатов.

Контр-аргументом для этого предложения является то, что семантика select в анализаторе достаточно сильно отличается от оператора switch.

G.2. Неопределенное поведение

Неопределенность поведения вызывает множество проблем в таких языках, как C и HTML, включая ошибки и серьезные уязвимости защиты. Есть несколько мест, где оценка программы P4 может приводить к неопределенному поведению — параметры out, неинициализированные переменные, доступ к полям недействительных заголовков или к стекам заголовков за пределами границы стека. Нужно сделать все возможное для устранения неопределенностей, в P416, поэтому предлагается усиливать формулировки спецификации, чтобы исключить описанное выше поведение в принятых по умолчанию случаях. С учетом заботы о производительности предлагается определить флаги компиляции и/или pragma для переопределения заданного по умолчанию поведения. Однако предполагается, что программистам следует создавать защищенные программы и более серьезно относиться к вопросам безопасности.

G.3. Структурированные итерации

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

foreach hdr in hdrs { /// операции над HDR }

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

Приложение H. Грамматика P4

Грамматика P416 описана на языке YACC/bison и не задает приоритет операций. Грамматика в реальности неоднозначна, поэтому лексер и синтаксический анализатор должны работать совместно. В частности, лексер должен различать ранее введенные идентификаторы типов (маркеры TYPE_IDENTIFIER) и обычные идентификаторы (маркер IDENTIFIER). Анализатор должен использовать таблицу символов, чтобы указывать лексеру, как следует разбирать последовательные идентификаторы. Например, для приведенного ниже фрагмента

typedef bit<4> t;
struct s { /* тело опущено */}
t x;
parser p(bit<8> b) { /* тело опущено */ }

лексер возвратит показанные ниже виды терминалов

t — TYPE_IDENTIFIER
s — TYPE_IDENTIFIER
x — IDENTIFIER
p — TYPE_IDENTIFIER
b — IDENTIFIER

На эту грамматику оказывают существенное влияние ограничения инструмента генерации анализаторов Bison.

Несколько других терминалов констант присутствуют в приведенных ниже правилах

MASK — это &&&
RANGE — это ..
DONTCARE — это _

Маркер STRING_LITERAL соответствует строковому литералу в двойных кавычках (6.3.3.3. Строковые литералы).

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

p4program
	: /* пусто */
	| p4program declaration
	| p4program ';'	/* пустое объявление */
	;

declaration
	: constantDeclaration
	| externDeclaration
	| actionDeclaration
	| parserDeclaration
	| typeDeclaration
	| controlDeclaration
	| instantiation
	| errorDeclaration
	| matchKindDeclaration
	| functionDeclaration
	;

nonTypeName
	: IDENTIFIER
	| APPLY
	| KEY
	| ACTIONS
	| STATE
	| ENTRIES
	| TYPE
	;

name
	: nonTypeName
	| TYPE_IDENTIFIER
	;

nonTableKwName
	: IDENTIFIER
	| TYPE_IDENTIFIER
	| APPLY
	| STATE
	| TYPE
	;

optAnnotations
	: /* пусто */
	| annotations
	;

annotations
	: annotation
	| annotations annotation
	;

annotation
	: '@' name
	| '@' name '(' annotationBody ')'
	| '@' name '[' structuredAnnotationBody ']'
	;

parameterList
	: /* пусто */
	| nonEmptyParameterList
	;

nonEmptyParameterList
	: parameter
	| nonEmptyParameterList ',' parameter
	;

parameter
	: optAnnotations direction typeRef name
	| optAnnotations direction typeRef name '=' expression
	;

direction
	: IN
	| OUT
	| INOUT
	: /* пусто */
	;

packageTypeDeclaration
	: optAnnotations PACKAGE name optTypeParameters
	'(' parameterList ')'
	;

instantiation
	: typeRef '(' argumentList ')' name ';'

	| annotations typeRef '(' argumentList ')' name ';'
	;

optConstructorParameters
	: /* пусто */
	| '(' parameterList ')'
	;

dotPrefix
	: '.'
	;

/**************************** Анализатор ******************************/
parserDeclaration
	: parserTypeDeclaration optConstructorParameters
	  /* параметры типа не разрешены в parserTypeDeclaration */
	  '{' parserLocalElements parserStates '}'
	;

parserLocalElements
	: /* пусто */
	| parserLocalElements parserLocalElement
	;

parserLocalElement
	: constantDeclaration
	| variableDeclaration
	| instantiation
	| valueSetDeclaration
	;

parserTypeDeclaration
	: optAnnotations PARSER name optTypeParameters '(' parameterList ')'
	;

parserStates
	: parserState
	| parserStates parserState
	;

parserState
	: optAnnotations STATE name '{' parserStatements transitionStatement '}'
	;

parserStatements
	: /* пусто */
	| parserStatements parserStatement
	;

parserStatement
	: assignmentOrMethodCallStatement
	| directApplication
	| parserBlockStatement
	| constantDeclaration
	| variableDeclaration
	| emptyStatement
	;

parserBlockStatement
	: optAnnotations '{' parserStatements '}'
	;

transitionStatement
	: /* пусто */
	| TRANSITION stateExpression
	;

stateExpression
	: name ';'
	| selectExpression
	;

selectExpression
	: SELECT '(' expressionList ')' '{' selectCaseList '}'
	;

selectCaseList
	: /* пусто */
	| selectCaseList selectCase
	;

selectCase
	: keysetExpression ':' name ';'
	;

keysetExpression
	: tupleKeysetExpression
	| simpleKeysetExpression
	;

tupleKeysetExpression
	: '(' simpleKeysetExpression ',' simpleExpressionList ')'
	;

simpleExpressionList
	: simpleKeysetExpression
	| simpleExpressionList ',' simpleKeysetExpression
	;

simpleKeysetExpression
	: expression
	| DEFAULT
	| DONTCARE
	| expression MASK expression
	| expression RANGE expression
	;

valueSetDeclaration
	: optAnnotations
	  VALUESET '<' baseType '>' '(' expression ')' name ';'
	| optAnnotations
	  VALUESET '<' tupleType '>' '(' expression ')' name ';'
	| optAnnotations
	  VALUESET '<' typeName '>' '(' expression ')' name ';'
	;

/*************************** Элемент управления ************************/
controlDeclaration
	: controlTypeDeclaration optConstructorParameters
	  /* параметры типа не разрешены в controlTypeDeclaration */
	  '{' controlLocalDeclarations APPLY controlBody '}'
	;

controlTypeDeclaration
	: optAnnotations CONTROL name optTypeParameters
	  '(' parameterList ')'
	;

controlLocalDeclarations
	: /* пусто */
	| controlLocalDeclarations controlLocalDeclaration
	;

controlLocalDeclaration
	: constantDeclaration
	| actionDeclaration
	| tableDeclaration
	| instantiation
	| variableDeclaration
	;

controlBody
	: blockStatement
	;

/*************************** Внешний объект *************************/
externDeclaration
	: optAnnotations EXTERN nonTypeName optTypeParameters '{' methodPrototypes '}'
	| optAnnotations EXTERN functionPrototype ';'
	;

methodPrototypes
	: /* пусто */
	| methodPrototypes methodPrototype
	;

functionPrototype
	: typeOrVoid name optTypeParameters '(' parameterList ')'
	;

methodPrototype
	: optAnnotations functionPrototype ';'
	| optAnnotations TYPE_IDENTIFIER '(' parameterList ')' ';'
	;

/************************** Типы ****************************/
typeRef
	: baseType
	| typeName
	| specializedType
	| headerStackType
	| tupleType
	;

namedType
	: typeName
	| specializedType
	;

prefixedType
	: TYPE_IDENTIFIER
	| dotPrefix TYPE_IDENTIFIER
	;

typeName
	: prefixedType
	;

tupleType
	: TUPLE '<' typeArgumentList '>'
	;

headerStackType
	: typeName '[' expression ']'
	;

specializedType
	: prefixedType '<' typeArgumentList '>'
	;

baseType
	: BOOL
	| ERROR
	| INT
	| BIT
	| BIT '<' INTEGER '>'
	| INT '<' INTEGER '>'
	| VARBIT '<' INTEGER '>'
	| BIT '<' '(' expression ')' '>'
	| INT '<' '(' expression ')' '>'
	| VARBIT '<' '(' expression ')' '>'
	;

typeOrVoid
	: typeRef
	| VOID
	| IDENTIFIER 	// может быть переменной типа
	;

optTypeParameters
	: /* пусто */
	| '<' typeParameterList '>'
	;

typeParameterList
	: name
	| typeParameterList ',' name
	;
realTypeArg
	: DONTCARE
	| typeRef
	;

typeArg
	: DONTCARE
	| typeRef
	| nonTypeName
	;

realTypeArgumentList
	: realTypeArg
	| realTypeArgumentList COMMA typeArg
	;

typeArgumentList
	: /* пусто */
	| typeArg
	| typeArgumentList ',' typeArg
	;

typeDeclaration
	: derivedTypeDeclaration
	| typedefDeclaration
	| parserTypeDeclaration ';'
	| controlTypeDeclaration ';'
	| packageTypeDeclaration ';'
	;

derivedTypeDeclaration
	: headerTypeDeclaration
	| headerUnionDeclaration
	| structTypeDeclaration
	| enumDeclaration
	;

headerTypeDeclaration
	: optAnnotations HEADER name '{' structFieldList '}'
	;

headerUnionDeclaration
	: optAnnotations HEADER_UNION name '{' structFieldList '}'
	;

structTypeDeclaration
	: optAnnotations STRUCT name '{' structFieldList '}'
	;

structFieldList
	: /* пусто */
	| structFieldList structField
	;

structField
	: optAnnotations typeRef name ';'
	;

enumDeclaration
	: optAnnotations ENUM name '{' identifierList '}'
	| optAnnotations ENUM BIT '<' INTEGER '>' name '{' specifiedIdentifierList '}'
	;

errorDeclaration
	: ERROR '{' identifierList '}'
	;

matchKindDeclaration
	: MATCH_KIND '{' identifierList '}'
	;

identifierList
	: name
	| identifierList ',' name
	;

specifiedIdentifierList
	: specifiedIdentifier
	| specifiedIdentifierList ',' specifiedIdentifier
	;

specifiedIdentifier
	: name '=' initializer
	;

typedefDeclaration
	: optAnnotations TYPEDEF typeRef name ';'
	| optAnnotations TYPEDEF derivedTypeDeclaration name ';'
	| optAnnotations TYPE typeRef name ';'
	| optAnnotations TYPE derivedTypeDeclaration name ';'
	;

/*************************** Операторы *************************/
assignmentOrMethodCallStatement
	: lvalue '(' argumentList ')' ';'
	| lvalue '<' typeArgumentList '>' '(' argumentList ')' ';'
	| lvalue '=' expression ';'
	;

emptyStatement
	: ';'
	;

returnStatement
	: RETURN ';'
	| RETURN expression ';'
	;

exitStatement
	: EXIT ';'
	;

conditionalStatement
	: IF '(' expression ')' statement
	| IF '(' expression ')' statement ELSE statement
	;

// для поддержки прямых вызовов элемента управления или анализатора
directApplication
	: typeName '.' APPLY '(' argumentList ')' ';'
	;

statement
	: assignmentOrMethodCallStatement
	| directApplication
	| conditionalStatement
	| emptyStatement
	| blockStatement
	| exitStatement
	| returnStatement
	| switchStatement
	;

blockStatement
	: optAnnotations '{' statOrDeclList '}'
	;

statOrDeclList
	: /* пусто */
	| statOrDeclList statementOrDeclaration
	;

switchStatement
	: SWITCH '(' expression ')' '{' switchCases '}'
	;

switchCases
	: /* пусто */
	| switchCases switchCase
	;

switchCase
	: switchLabel ':' blockStatement
	| switchLabel ':'
	;

switchLabel
	: name
	| DEFAULT
	;

statementOrDeclaration
	: variableDeclaration
	| constantDeclaration
	| statement
	| instantiation
	;

/************ Таблицы *************/
tableDeclaration
	: optAnnotations TABLE name '{' tablePropertyList '}'
	;

tablePropertyList
	: tableProperty
	| tablePropertyList tableProperty
	;

tableProperty
	: KEY '=' '{' keyElementList '}'
	| ACTIONS '=' '{' actionList '}'
	| CONST ENTRIES '=' '{' entriesList '}' /* immutable entries */
	| optAnnotations CONST nonTableKwName '=' initializer ';'
	| optAnnotations nonTableKwName '=' initializer ';'
	;

keyElementList
	: /* пусто */
	| keyElementList keyElement
	;

keyElement
	: expression ':' name optAnnotations ';'
	;

actionList
	: /* пусто */
	| actionList optAnnotations actionRef ';'
	;

actionRef
	: prefixedNonTypeName
	| prefixedNonTypeName '(' argumentList ')'
	;

entriesList
	: entry
	| entriesList entry
	;

entry
	: keysetExpression ':' actionRef optAnnotations ';'
	;

/************************* Действия ********************************/
actionDeclaration
	: optAnnotations ACTION name '(' parameterList ')' blockStatement
	;

/************************* Переменные *****************************/
variableDeclaration
	: annotations typeRef name optInitializer ';'
	| typeRef name optInitializer ';'
	;

constantDeclaration
	: optAnnotations CONST typeRef name '=' initializer ';'
	;
optInitializer
	: /* пусто */
	| '=' initializer
	;

initializer
	: expression
	;

/************************* Выражения ****************************/
functionDeclaration
	: functionPrototype blockStatement
	;

argumentList
	: /* пусто */
	| nonEmptyArgList
	;

nonEmptyArgList
	: argument
	| nonEmptyArgList ',' argument
	;

argument
	: expression
	| name '=' expression
	| DONTCARE
	;

kvList
	: kvPair
	| kvList ',' kvPair
	;

kvPair
	: name '=' expression
	;

expressionList
	: /* пусто */
	| expression
	| expressionList ',' expression
	;

annotationBody
	: /* пусто */
	| annotationBody '(' annotationBody| annotationBody annotationToken
	  structuredAnnotationBody
	: expressionList
	| kvList
	;

annotationToken
	: ABSTRACT
	| ACTION
	| ACTIONS
	| APPLY
	| BOOL
	| BIT
	| CONST
	| CONTROL
	| DEFAULT
	| ELSE
	| ENTRIES
	| ENUM
	| ERROR
	| EXIT
	| EXTERN
	| FALSE
	| HEADER
	| HEADER_UNION
	| IF
	| IN
	| INOUT
	| INT
	| KEY
	| MATCH_KIND
	| TYPE
	| OUT
	| PARSER
	| PACKAGE
	| PRAGMA
	| RETURN
	| SELECT
	| STATE
	| STRUCT
	| SWITCH
	| TABLE
	| THIS
	| TRANSITION
	| TRUE
	| TUPLE
	| TYPEDEF
	| VARBIT
	| VALUESET
	| VOID
	| "_"
	| IDENTIFIER
	| TYPE_IDENTIFIER
	| STRING_LITERAL
	| INTEGER
	| "&&&"
	| ".."
	| "<<"
	| "&&"
	| "||"
	| "=="
	| "!="
	| ">="
	| "<="
	| "++"
	| "+"
	| "|+|"
	| "-"
	| "|-|"
	| "*"
	| "/"
	| "%"
	| "|"
	| "&"
	| "^"
	| "~"
	| "["
	| "]"
	| "{"
	| "}"
	| "<"
	| ">"
	| "!"
	| ":"
	| ","
	| "?"
	| "."
	| "="
	| ";"
	| "@"
	| UNKNOWN_TOKEN

member
	: name
	;
	
prefixedNonTypeName
	: nonTypeName
	| dotPrefix nonTypeName
	;

lvalue
	: prefixedNonTypeName
	| lvalue '.' member
	| lvalue '[' expression ']'
	| lvalue '[' expression ':' expression ']'
	;

%left ','
%nonassoc '?'
%nonassoc ':'
%left '||'
%left '&&'
%left '==' '!='
%left '<' '>' '<=' '>='
%left '|'
%left '^'
%left '&'
%left '<<' '>>'
%left '++' '+' '-' '|+|' '|-|'
%left '*' '/' '%'
%right PREFIX
%nonassoc ']' '(' '['
%left '.'

// Дополнительные предпочтения, которые нужно задать
expression
	: INTEGER
	| TRUE
	| FALSE
	| STRING_LITERAL
	| nonTypeName
	| dotPrefix nonTypeName
	| expression '[' expression ']'
	| expression '[' expression ':' expression ']'
	| '{' expressionList '}'
	| '{' kvList '}'
	| '(' expression ')'
	| '!' expression %prec PREFIX
	| '~' expression %prec PREFIX
	| '-' expression %prec PREFIX
	| '+' expression %prec PREFIX
	| typeName '.' member
	| ERROR '.' member
	| expression '.' member
	| expression '*' expression
	| expression '/' expression
	| expression '%' expression
	| expression '+' expression
	| expression '-' expression
	| expression '|+|' expression
	| expression '|-|' expression
	| expression '<<' expression
	| expression '>>' expression
	| expression '<=' expression
	| expression '>=' expression
	| expression '<' expression
	| expression '>' expression
	| expression '!=' expression
	| expression '==' expression
	| expression '&' expression
	| expression '^' expression
	| expression '|' expression
	| expression '++' expression
	| expression '&&' expression
	| expression '||' expression
	| expression '?' expression ':' expression
	| expression '<' realTypeArgumentList '>' '(' argumentList ')'
	| expression '(' argumentList ')'
	| namedType '(' argumentList ')'
	| '(' typeRef ')' expression
	;

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

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

nmalykh@protokols.ru

1Перевод статьи доступен на сайте www.protokols.ru. Прим. перев.

2Very Simple Switch — очень простой коммутатор.

3Старших битов. Прим. перев.

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

Рубрика: SDN, Сетевое программирование | Комментарии к записи Спецификация языка P4_16, версия 1.2.1 отключены

RFC 8793 Information-Centric Networking (ICN): Content-Centric Networking (CCNx) and Named Data Networking (NDN) Terminology

Internet Research Task Force (IRTF)                          B. Wissingh
Request for Comments: 8793                                           TNO
Category: Informational                                          C. Wood
ISSN: 2070-1721                          University of California Irvine
                                                            A. Afanasyev
                                        Florida International University
                                                                L. Zhang
                                                                    UCLA
                                                                 D. Oran
                                       Network Systems Research & Design
                                                             C. Tschudin
                                                     University of Basel
                                                               June 2020

Информационно-ориентированные сети — терминология CCNx и NDN

PDF

Аннотация

Информационно-ориентированные сети (ICN1) — это новая парадигма, где сетевые коммуникации выполняются путем запроса именованного содержимого (content) вместо отправки пакетов по адресам получателей. Примерами архитектуры ICN являются сети именованных данных (NDN2) и контентно-ориентированные сети (CCNx3). В этом документе представлен обзор терминологии и определений, которые могут использоваться при описании концепций этих двух реализаций ICN. Имеются и другие архитектуры ICN, не являющиеся частью концепций NDN и CCNx, но они выходят за рамки этого документа. Документ является результатом работы исследовательской группы ICNRG4.

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

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

Документ создан в Internet Research Task Force (IRTF). IRTF публиуует результаты связанных с Internet исследований и разработок. Эти результаты могут оказаться не пригодными для реализации. Данный документ RFC выражает согласованную точку зрения ICNRG и IRTF. Документы, одобренные для публикации IRSG, не претендуют на статус стандартов Internet (см. раздел 2 в RFC 7841).

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

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

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

К документу применимы права и ограничения, указанные в BCP 78 и IETF Trust Legal Provisions и относящиеся к документам IETF (http://trustee.ietf.org/license-info), на момент публикации данного документа. Прочтите упомянутые документы внимательно.

1. Введение

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

Поскольку разработка этого направления продолжается, появляется много новых терминов. Целью данного документа является сбор ключевых терминов с их определениями, применяемыми в проектах CCNx и NDN. Важными для этих проектов документами являются [RFC8569], [RFC8609] и [NDNTLV]. Другие проекты ICN, такие как [NETINF], [PSIRP], [MOBILITY-FIRST] не рассматриваются здесь, но могут быть предметом других документов.

Для обеспечения контекста некоторых из определяемых здесь терминов сначала обрисована общая картина ICN путем введения базовых концепций и указания основных компонентов в разделе 2. Затем в разделе 3 рассматриваются относящиеся к ICN термины, разделенные по категориям. Следует отметить, что при такой организации некоторые термины могут применяться до их определения.

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

Документ представляет согласованную точку зрения ICNRG. Он широко обсуждался членами исследовательской группы (RG5), занимающимися конкретными направлениями, рассматриваемыми в документе. Документ не является результатом работы IETF и не предназначен для стандартизации в IETF.

2. Набросок общей картины ICN

В сетевом смысле ICN является инфраструктурой для доставки именованных данных, более полное описание которой дано в разделе 4.

запрашивающий   необязательные         узел-источник 
    (узел)      узлы пересылки           или реплика
  |                 | ... |                  |...|
  |   Interest(n)   |     |   Interest(n)    |   |
  | --------------> |     | ---------------> |   |
  |                 |     | -------------------> |
  |                 |     |                  |   |
  |                 |     |  Data([n],c,[s]) |   |
  |                 |     | <--------------- |   |
  |                 |     | <------------------- |
  | Data([n],c,[s]) |     |                  |   |
  | <-------------- |     |                  |   |

n - имя, c - содержимое, s - подпись

Рисунок 1. Протокол «запрос-отклик в сети ICN.


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

Request-Reply Protocol (пакеты Interest и Packet) — протокол “запрос-отклик”

Услуги поиска в ICN реализуются через определение двух форматов сетевых пакетов — Interest с запросом содержимого по имени и Data с запрошенным содержимым. Возвращаемые пакеты Data должны соответствовать параметрам запроса (например, полное или частичное совпадение имени). Если запрос не однозначен и ему соответствует несколько пакетов Data, сеть ICN возвращает лишь один подходящий пакет Data (это балансирует пакеты Interest и Data через отдельный интерфейс L2).

Packet and Content Names — пакеты и имена содержимого

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

Data Authenticity and Encryption — шифрование и аутентичность данных

Любой потребитель или элемент сети может (в принципе) проверить аутентичность пакета Data на основании криптографической привязки между именем и содержимым. Отметим, что аутентичность данных не тождественна доверию к ним, хотя они связаны между собой. Пакет считается аутентичным, если он имеет действительную привязку имени к содержимому, но это не предполагает обязательного «доверия» к нему.

Trust — доверие

Аутентичность данных отличается от доверия к ним, хотя эти концепции связаны. Пакет считается аутентичным при наличии действительной привязки имени к содержимому. Пакет считается доверенным (т. е. происходящим от «уважаемого» или достоверного источника), если привязка действительна в контексте модели доверия. Модель доверия предполагает доверие к тому, что имя, присвоенное определенной порции данных, действительно для их содержимого. Дополнительно этот вопрос рассматривается в разделе 6.

Segmenting and Versioning — сегментация и версии

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

Packet and Frame — пакет и кадр

NDN и CCNx используют протокольные блоки данных (PDU6), которые обычно больше максимального передаваемого блока базовой сетевой технологии. Здесь PDU называются пакетами и (возможно фрагментированными) частями пакетов, проходящими через интерфейс L2 с ограниченным MTU как кадры. Обработка на уровне L2, ведущая к фрагментированию пакетов ICN, выполняется внутри сети ICN и не видна сервисному интерфейсу.

ICN Node — узел ICN

Узел в сети ICN может играть роль производителя данных (producer), их потребителя (consumer) и/или пересылающего пакеты Interest и Data. При соединении узла пересылки с соседями он в реальном масштабе времени пересылает пакеты Interest и Data. Этот узел может также служить промежуточным хранилищем, удерживающим на некоторое время пакеты Interest и Data перед их отправкой следующему узлу. На узле ICN могут также применяться протоколы маршрутизации для оказания помощи в пересылке пакетов Interest.

Forwarding Plane — плоскость (уровень) пересылки

Канонический способ реализации пересылки пакетов в сети ICN базируется на 3 структурах данных, фиксирующих состояние узла, — FIB7, PIT8 и CS9. Применяются также стратегии пересылки Interest, принимающие данные от FIB и измерителей для принятия решений о пересылке Interest. Получив пакет Interest, узел проверяет CS и PIT для поиска подходящей записи. Если такой записи не найдено, узел записывает Interest в свою таблицу PIT и пересылает Interest на следующий интервал (интервалы) по пути к запрошенному содержимому на основе информации из своей базы FIB.

3. Термины

3.1. Базовые термины

Information-Centric Networking (ICN) — информационно-ориентированная сеть

Сетевая архитектура, отыскивающая пакеты данных (Data) в ответ на запросы Interest. Двумя реализациями ICN служат ориентированные на соединения сети CCNx (1.x) и сети именованных данных NDN.

Data Packet Immutability — неизменяемость пакетов данных

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

3.2. Термины, относящиеся к узлам ICN

ICN Interface — интерфейс ICN

Обобщение сетевого интерфейса, которое может представлять физический интерфейс (ethernet, Wi-Fi, bluetooth и т. п.), наложенный канал между узлами (туннель IP/UDP и т. п.) или канал IPC10 с приложением (сокет unix, общая память и т. п.).

Синоним — face.

ICN Consumer — потребитель ICN

Элемент ICN, запрашивающий пакеты Data путем создания и отправки пакетов Interest в направлении локального (через интерфейс внутри узла) или удаленного (через внешний интерфейс узла) узла пересылки ICN.

Синонимы — consumer, information consumer, data consumer, consumer of the content.

ICN Producer — производитель (издатель) ICN

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

Синонимы — producer, publisher, information publisher, data publisher, data producer.

ICN Forwarder — пересылающий узел ICN

Элемент ICN, реализующий пересылку с учетом состояния.

Синоним — ICN router.

ICN Data Node — узел данных ICN

Элемент ICN, временно сохраняющий и потенциально содержащий пакет Interest или Data перед его пересылкой следующему элементу ICN. Отметим, что такие узлы ICN не обладают всеми свойствами узлов данных, используемыми в спецификации DTN11 [RFC4838].

3.3. Термины, связанные с пересылкой

Stateful Forwarding — пересылка с учетом состояния

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

Синонимы — ICN Data plane, ICN Forwarding.

Forwarding Strategy — стратегия пересылки

Модуль пересылки ICN с учетом состояния (ICN data), принимающие решение о том, куда и как переслать входящий пакет Interest. Стратегия пересылки принимает также данные FIB, параметры производительности плоскости данных и/или использует иные механизмы для принятия решений.

Синоним — Interest forwarding strategy.

Upstream — восходящая (пересылка)

Пересылка пакетов в направлении Interest (т. е. пакеты Interest пересылаются в восходящем направлении — потребитель, маршрутизатора, маршрутизатор, …, издатель.

Downstream — нисходящая (пересылка)

Пересылка пакетов в направлении, обратном пересылке Interest (пакеты Data и Interest Nack пересылаются в нисходящем направлении): издатель, маршрутизатор, …, потребители.

Interest Forwarding — пересылка Interest

Процесс пересылки пакетов Interest с использованием Name из этих пакетов. При пересылке с учетом состояния это включает также создание записи в PIT. Решение о пересылке принимает Forwarding Strategy.

Interest Aggregation — агрегирование Interest

Процесс объединения множества пакетов Interest с одним Name и дополнительными ограничениями для тех же Data в одну запись PIT.

Синоним — Interest collapsing.

Data Forwarding — пересылка данных

Процесс пересылки входящих пакетов Data интерфейсам, указанным в соответствующих записях PIT и удаления этих записей.

Satisfying an Interest — выполнение Interest

Процесс возврата содержимого в целом, удовлетворяющий ограничениям, заданным в Interest (прежде всего, совпадение Name).

Interest Match in FIB (longest prefix match) — совпадение Interest в FIB по самому длинному префиксу

Процесс нахождения записи FIB с наибольшим совпадением префикса (по числу компонентов Name), являющимся префиксом указанного Name (см. 3.5. Термины, связанные с типами имен).

Interest Match in PIT (exact match) — точное совпадение Interest в FIB

Процесс нахождения записи PIT с тем же Name, что указано в Interest (включая ограничения Interest при наличии).

Data Match in PIT (all match) — полное совпадение Data в FIB

Процесс нахождения набора записей PIT, которым может соответствовать указанный пакет Data.

Interest Match in CS (any match) — совпадение Interest в CS

Процесс нахождения записи в Content Store маршрутизатора, соответствующей заданному пакету Interest.

Pending Interest Table (PIT) — таблица ожидающих Interest

База данных с записями полученных, но еще не выполненных Interest с указанием интерфейсов, принявших запросы. PIT может также включать интерфейсы, в которые пересланы Interest, ссылки для доступа к сведениям о производительности плоскости данных. Пакеты Interest до одних Data объединяются в одну запись PIT.

Forwarding Information Base (FIB) — база информации о пересылке

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

Content Store (CS) — хранилище содержимого

База данных для кэширования в маршрутизаторе ICN.

In-Network Storage — хранилище в сети

Необязательный процесс хранения пакетов Data внутри сети (opportunistic cache, dedicated on/off path cache, managed in-network storage system) для выполнения будущих запросов Interest к тем же Data. Хранилища могут анонсировать сохраненные пакеты Data в систему маршрутизации.

Opportunistic Caching

Процесс временного хранения пересланных пакетов Data в памяти маршрутизатора (RAM или диск) для их использования в ответах на будущие Interest для тех же Data.

Синоним — on-path in-network caching.

Managed Caching — управляемое кэширование

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

Синоним — off-path in-network storage.

Managed In-Network Storage — управляемое хранилище в сети

Элемент, выступающий как издатель ICN, который реализует управляемое кэширование.

Синонимы — repository, repo.

ICN Routing Plane — плоскость маршрутизации ICN

Протокол или набор протоколов ICN для обмена информацией о доступности пространства имен (Name).

ICN Routing Information Base (RIB) — информационная база маршрутизации ICN

База данных с набором отображений префикс-интерфейс, создаваемых работой одного или множества протоколов маршрутизации. RIB используется для заполнения FIB.

3.4. Термины, связанные с типами пакетов

Interest Packet — пакет Interest

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

Синонимы — Interest, Interest message, information request.

Interest Nack — негативное подтверждение Interest

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

Синонимы — network NACK, Interest return.

Data Packet — пакет Data

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

Синонимы — data, data object, content object, content object packet, data message, named data object, named data.

Link — привязка

Тип пакета Data, тело которого содержит имя (Name) другого пакета Data. Это внутреннее имя часто является полным, т. е. указывает Packet ID соответствующего пакета Data, но это не является требованием.

Синоним — pointer.

Manifest — манифест

Тип пакета Data, содержащего привязки полного имени для одного или нескольких пакетов Data. Манифесты группируют коллекции связанных пакетов Data с одним Name. Манифесты позволяют разбивать большие объекты Data на отдельные Content Object с одним именем, а также представлять наборы связанных Content Object как форму «каталога» (directory). Дополнительным преимуществом манифестов является снижение издержек на верификацию подписей для каждого пакета Data, упомянутого во внутренних Link. Манифесты обычно содержат дополнительные метаданные, например, размер (в байтах) каждого привязанного пакета Data и криптографический хэш-дайджест всех Data, содержащихся в связанных пакетах Data.

3.5. Термины, связанные с типами имен

Name

Идентификатор пакета Data. Имена в ICN организованы иерархически (последовательность меток) и обычно семантически значимы, что делает их выразительными, гибкими и специфичными для приложения (подобно HTTP URL). Name может кодировать информацию о контексте приложения, семантике, местоположении (топология, география и т. п.), имени сервиса и т. п.

Синонимы — data name, interest name, content name.

Name component — компонент Name

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

Синоним — name segment (как в CCNx).

Packet ID

Уникальный криптографический идентификатор пакета Data. Обычно это криптографический дайджест пакета Data (например, SHA256 [RFC6234]), учитывающая имя, данные, метаинформацию и подпись.

Синоним — implicit digest.

Selector — селектор

Механизм (условие) выбора отдельного пакета Data из коллекции, соответствующего данному пакету Interest, запрашивающему данные с использованием префикса или точного имени.

Синонимы — interest selector, restrictor, interest restrictor.

Nonce

Поле пакета Interest, временно указывающее экземпляр Interest (для данного имени). Отметим, что определение nonce в спецификации NDN не обязательно соответствует всем свойствам nonce из [RFC4949].

Exact Name — точное имя

Имя, указанное в пакете Data, которое обычно однозначно указывает данный пакет Data.

Full Name — полное имя

Точное имя с Packet ID соответствующего пакета Data.

Prefix Name — префикс имени

Name с частью последовательности меток (начиная с первой) из Name в пакете Data.

Синоним — prefix.

3.6. Термины, связанные с использованием имен

Naming conventions — соглашения об именовании

Соглашение, договор или спецификация именования пакетов Data, структурирующие пространство имен.

Синонимы — Naming scheme, ICN naming scheme, namespace convention.

Hierarchically structured naming — иерархически структурированное именование

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

Синонимы — hierarchical naming, structured naming.

Flat naming — плоское именование

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

Segmentation — сегментация

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

Синоним — chunking.

Versioning — поддержка версий

Процесс назначения уникального имени (Name) выпуску содержимого в определенном пакете Data. При использовании в Name с иерархической структурой версия пакета Data может передаваться в отдельной метке Name (например, префикс указывает данные, а уникальный номер — их версию).

Fragmentation — фрагментация

Процесс расщепления PDU на кадры (Frame), которые можно передать через интерфейс L2 с меньшим MTU.

3.7. Термины, связанные с безопасностью

Data-Centric Security — защита данных

Свойство защиты, связанное с пакетом Data, включая целостность данных, их достоверность (authenticity) и, возможно, конфиденциальность. Эти свойства защиты остаются с пакетом Data независимо от места хранения и способа извлечения.

Синоним — directly securing Data packet.

Data Integrity — целостность данных

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

Data Authenticity — достоверность данных

Криптографический механизм обеспечения достоверности пакета Data на основе выбранной (например, издателем и/или потребителем) модели доверия. Обычно аутентичность данных обеспечивается за счет использования криптографических подписей с асимметричным шифрованием (например, RSA, ECDSA), но может применяться и симметричное шифрование (например, HMAC12) внутри домена доверия.

Data Confidentiality — конфиденциальность данных

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

Content Confidentiality — конфиденциальность содержимого

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

Name Confidentiality — конфиденциальность имени

Криптографический механизм, предотвращающий получение мета-информации из пакета Data наблюдателю обмена Interest-Data (например, промежуточному маршрутизатору). Этот механизм может быть реализован на основе шифрования Data (как конфиденциальность содержимого) или «затемнения» (obfuscation).

4. Семантика и применение

Описанная выше терминология является обнародованием предполагаемой семантики операций NDN и CCNx (что ожидается в сети). Далее кратко рассмотрены наиболее часто предлагаемые варианты применения и интерпретации.

4.1. Передача данных

Представление сети NDN и CCNx основано на допущение о том, что протокол запрос-отклик реализует базовые услуги передачи данных без гарантии доставки для одиночных именованных пакетов.

4.2. Транспортировка данных

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

4.3. Служба поиска

В более распределенных системном представлении базового протокола запрос-отклик NDN и CCNx обеспечивают распределенную службу поиска, возвращающую значение, найденное по ключу (=name).

4.4. Доступ к базе данных

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

4.5. Вызов удаленных процедур

Имена, определенные в этом документе для Interest и Data, могут указывать на вызовы удаленных процедур, их входные аргументы и результаты. Для полного представления о создании RPC и работе с другими системами удаленных вызовов следует обратиться к работе [RICE]. Эти возможности могут быть расширены в полную инфраструктуру распределенной обработки, как предложено в работе [CFN].

4.6. Публикация и подписка

Имена, определенные в этом документе для Interest и Data, могут указывать коллекции данных, на которые можно подписаться, а также отдельные объекты данных, публикуемые в архитектуре Publish-Subscribe. Пример создания таких систем на основе ICN приведен в работе [LESSONS-LEARNED].

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

Этот документ не предполагает действий IANA.

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

Хотя определенные здесь термины сами по себе не создают новых вопросов безопасности, использующие эти термины архитектуры могут вызывать такие вопросы. Следует обратиться к спецификации архитектуры (например, [RFC8569] и [NDN]), где вопросы безопасности рассматриваются подробно.

Некоторые из терминов в этом документе используют понятия «доверие» (trust), «заслуживающий доверия» (trustworthy) и «модель доверия» (trust model). Предполагается, что эти термины имеют общепринятый смысл, однако в недавнее время было опубликовано множество работ, посвященных доверию и, в частности, схемам доверия в архитектуре ICN. Например, полезно прочесть работу [SCHEMATIZING-TRUST], где более подробно рассмотрена формализация доверия для современных систем NDN и CCNx.

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

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

[CFN] Krol, M., Mastorakis, S., Kutscher, D., and D. Oran, «Compute First Networking: Distributed Computing meets ICN»13, ACM ICN, DOI 10.1145/3357150.3357395, September 2019, <https://dl.acm.org/citation.cfm?id=3357395>.

[LESSONS-LEARNED] Nichols, K., «Lessons Learned Building a Secure Network Measurement Framework using Basic NDN»14, ACM ICN, DOI 10.1145/3357150.3357397, September 2019, <https://dl.acm.org/citation.cfm?id=3357397>.

[MOBILITY-FIRST] Raychaudhuri, D., Nagaraja, K., and A. Venkataramani, «MobilityFirst: a robust and trustworthy mobility-centric architecture for the future internet»15, ACM SIGMOBILE, Volume 16, Issue 3, DOI 10.1145/2412096.2412098, July 2012, <https://dl.acm.org/citation.cfm?id=2412098>.

[NDNTLV] Named Data Networking, «NDN Packet Format Specification», <https://named-data.net/doc/ndn-tlv/>.

[NETINF] Dannewitz, C., Kutscher, D., Ohlman, B., Farrell, S., Ahlgren, B., and K. Holger, «Network of Information (NetInf) — An information-centric networking architecture», Computer Communications, Volume 36, Issue 7, DOI 10.1016/j.comcom.2013.01.009, April 2013, <https://dl.acm.org/citation.cfm?id=2459643>.

[PSIRP] Trossen, D., Tuononen, J., Xylomenos, G., Sarela, M., Zahemszky, A., Nikander, P., and T. Rinta-aho, «From Design for Tussle to Tussle Networking: PSIRP Vision and Use Cases», May 2008, <http://www.psirp.org/files/Deliverables/PSIRP-TR08-0001_Vision.pdf>.

[RICE] Krol, M., Habak, K., Kutscher, D., Oran, D., and I. Psaras, «RICE: remote method invocation in ICN»16, ACM ICN, DOI 10.1145/3267955.3267956, September 2018, <https://dx.doi.org/10.1145/3267955.3267956>.

[SCHEMATIZING-TRUST] Yu, Y., Afanasyev, A., Clark, D., Claffy, K. C., Jacobson, V., and L. Zhang, «Schematizing Trust in Named Data Networking»17, ACM ICN, DOI 0.1145/2810156.2810170, September 2015, <https://dx.doi.org/10.1145/2810156.2810170>.

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

[NDN] Named Data Networking, «Named Data Networking: Executive Summary», September 2010, <https://named-data.net/project/execsummary/>.

[RFC4838] Cerf, V., Burleigh, S., Hooke, A., Torgerson, L., Durst, R., Scott, K., Fall, K., and H. Weiss, «Delay-Tolerant Networking Architecture», RFC 4838, DOI 10.17487/RFC4838, April 2007, <https://www.rfc-editor.org/info/rfc4838>.

[RFC4949] Shirey, R., «Internet Security Glossary, Version 2», FYI 36, RFC 4949, DOI 10.17487/RFC4949, August 2007, <https://www.rfc-editor.org/info/rfc4949>.

[RFC6234] Eastlake 3rd, D. and T. Hansen, «US Secure Hash Algorithms (SHA and SHA-based HMAC and HKDF)», RFC 6234, DOI 10.17487/RFC6234, May 2011, <https://www.rfc-editor.org/info/rfc6234>.

[RFC8569] Mosko, M., Solis, I., and C. Wood, «Content-Centric Networking (CCNx) Semantics», RFC 8569, DOI 10.17487/RFC8569, July 2019, <https://www.rfc-editor.org/info/rfc8569>.

[RFC8609] Mosko, M., Solis, I., and C. Wood, «Content-Centric Networking (CCNx) Messages in TLV Format», RFC 8609, DOI 10.17487/RFC8609, July 2019, <https://www.rfc-editor.org/info/rfc8609>.

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

Marc Mosko предоставил много рекомендаций и точных указаний для правильных формулировок и определений терминов. Marie-Jose Montpetit подготовила рецензию IRSG, что помогло существенно улучшить текст. Дополнительные замечания при опросе IRSG от Stephen Farrell, Ari Keraenen, Spencer Dawkins, Carsten Bormann, Brian Trammell помогли улучшить документ. Полезные комментарии были получены в рамках обзора конфликтов IESG от Mirja Kuehlewind и Benjamin Kaduk.

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

Bastiaan Wissingh

TNO

Email: bastiaan.wissingh@tno.nl

Christopher A. Wood

University of California Irvine

Email: caw@heapingbits.net

Alex Afanasyev

Florida International University

Email: aa@cs.fiu.edu

Lixia Zhang

UCLA

Email: lixia@cs.ucla.edu

David Oran

Network Systems Research & Design

Email: daveoran@orandom.net

Christian Tschudin

University of Basel

Email: christian.tschudin@unibas.ch

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

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

nmalykh@protokols.ru


1Information-Centric Networking.

2Named Data Networking.

3Content-Centric Networking.

4Information-Centric Networking Research Group — группа исследований по информационно-ориентированным сетям.

5Research Group.

6Protocol Data Unit.

7Forwarding Interest Base — база пересылки Interest.

8Pending Interest Table — таблица ожидающих Interest.

9Content Store — хранилище содержимого.

10Inter-process communication — коммуникации между процессами на узле.

11Delay Tolerant Networking — устойчивая к задержкам сеть.

12Hashed Message Authentication Code — хэшированный код аутентификации сообщения.

13Презентация доклада доступна по ссылке. Прим. перев.

14Полный текст работы доступен по ссылке. Прим. перев.

15Полный текст работы доступен по ссылке. Прим. перев.

16Презентация доклада доступна по ссылке. Прим. перев.

17Полный текст работы доступен по ссылке. Прим. перев.

Рубрика: RFC | Комментарии к записи RFC 8793 Information-Centric Networking (ICN): Content-Centric Networking (CCNx) and Named Data Networking (NDN) Terminology отключены

RFC 8792 Handling Long Lines in Content of Internet-Drafts and RFCs

Internet Engineering Task Force (IETF)                         K. Watsen
Request for Comments: 8792                               Watsen Networks
Category: Informational                                     E. Auerswald
ISSN: 2070-1721                                   Individual Contributor
                                                               A. Farrel
                                                      Old Dog Consulting
                                                                   Q. Wu
                                                     Huawei Technologies
                                                               June 2020

Handling Long Lines in Content of Internet-Drafts and RFCs

Обработка длинных строк в Internet-Draft и RFC

PDF

Аннотация

Этот документ определяет две стратегии обработки длинных строк в документах с ограниченной шириной текста. Одна стратегия (single backslash) основана на сложившейся практике применения символа \ для указания раздела строки с продолжением с первого непробельного ( ) символа следующей строки. Другая стратегия (double backslash) расширяет первую, добавляя ещё один символ \ для указания продолжения, что позволяет обрабатывать более сложные ситуации. В обеих стратегиях применяется самоописывающий заголовок, позволяющий автоматически восстанавливать исходное содержимое.

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

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

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

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

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

Copyright (c) 2020. Авторские права принадлежат 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. Введение

[RFC7994] задаёт требования к текстовым документам RFC и указывает, что каждая строка RFC (и Internet-Draft) должна быть не длиннее 72 символов, после чего должен следовать characters followed by the character sequence that denotes an end-of-line (EOL).

В Internet-Draft и RFC часто включаются примеры текста и фрагменты кода, в которых строки могут включать более 72 символов. Утилита xml2rfc [xml2rfc] на момент публикации этого документа не пыталась фальцевать (wrap)содержимое таких включений, а просто выдавала предупреждения для строк длиннее 69 символов. Исторически сложилось так, что RFC Editor не давал каких-либо рекомендаций по обработке длинных строк в таких включениях, кроме совета авторам указывать произведенные манипуляции.

Этот документ определяет две стратегии обработки длинных строк в документах с ограниченной шириной текста. Одна стратегия (single backslash) основана на сложившейся практике применения символа \ для указания раздела строки с продолжением с первого непробельного ( ) символа следующей строки. Другая стратегия (double backslash) расширяет первую, добавляя ещё один символ \ для указания продолжения, что позволяет обрабатывать более сложные ситуации. В обеих стратегиях применяется самоописывающий заголовок, позволяющий автоматически восстанавливать исходное содержимое.

Описанные в документе стратегии работают с любым текстовым содержимым, но предназначены в основном для структурированных последовательностей строк, указанных элементом <sourcecode>, определённым в параграфе 2.48 [RFC7991], а не «двухмерных» изображений, таких как отмеченные элементом <artwork>, определенным в параграфе 2.5 [RFC7991].

Отметим, что текстовые файлы представляются строками, начинающимися с позиции 1 и имеющими размер N символов, где последний символ имеет номер N и сразу за ним следуют символы завершения строки.

2. Заявление о применимости

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

В рамках IETF эта работа нацелена, прежде всего, на элемент xml2rfc v3 <sourcecode> (параграф 2.48 в [RFC7991]) и элемент xml2rfc v2 <artwork> (параграф 2.5 в [RFC7749]), которые, за неимением лучшего варианта, используются в xml2rfc v2 для исходного кода и иллюстраций. Эта работа может применяться и с элементом xml2rfc v3 <artwork> (параграф 2.5 в [RFC7991]), но, как указано в параграфе 5.1, в общем случае это не рекомендуется.

3. Уровни требований

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

4. Цели

4.1. Автоматическая фальцовка длинных строк тестового содержимого

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

Во многие документы нужно включать содержимое из локальных файлов (например, XML, JSON, ABNF, ASN.1). Перед включением содержимого процессу сборки следует сначала проверить эти файлы с помощью соответствующих формату инструментов. Чтобы такие инструменты могли обработать файлы, те должны быть в своём исходном состоянии, что может предполагать наличие длинных строк. Таким образом, эти файлы потребуется сфальцевать перед включением в документ XML, чтобы выполнить ограничения по размеру строк в xml2rfc.

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

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

4.2. Автоматическое восстановление исходного содержимого

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

Например, модули YANG [RFC7950] извлекаются из Internet-Draft и проверяются в процессе представления. Кроме того, обсуждалось желание проверять экземпляры примеров (например, документов XML и JSON), содержащихся в Internet-Drafts [yang-doctors-thread].

5. Ограничения

5.1. Не рекомендуется для графических элементов

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

По сути, проблема состоит в читаемости содержимого после фальцовки. Непредсказуемый текст особенно плохо выгляти в сфальцованном виде и в эту категорию попадает большинство диаграмм унифицированного языка моделирования (Unified Modeling Language или UML), деревьев YANG, «рисунков» ASCII в целом.

Не рекомендуется применять представленное в документе решение для графических элементов.

5.2. Работает не так хорошо, как связанные с форматом опции

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

Например, утилиты pyang [pyang] и yanglint [yanglint] имеют опцию команды tree-line-length, которая позволяет указать желаемый максимальный размер строки при генерации диаграмм деревьев YANG [RFC8340].

В другом случае некоторые исходные форматы (например, YANG [RFC7950]) позволяют любую строку в кавычках разбить на несколько подстрок, разделённых символом конкатенации (например, +), каждая из которых может размещаться в отдельной строке текста.

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

6. Две стратегии фальцовки

Этот документ задаёт две похожих стратегии фальцовки текстового содержимого.

Single Backslash (‘\’)

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

Double Backslash (‘\\’)

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

6.1. Сравнение

Первая стратегия создаёт более удобочитаемый результат. Однако (1) весьма вероятно встретить нефальцуемый ввод (например, длинная строка пробелов) и (2) длинные строки, которые можно автоматически сфальцевать, могут приводить к необходимости специальной обработки для предотвращения ошибок.

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

6.2. Рекомендация

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

7. Стратегия Single Backslash (\)

7.1. Сфальцованная структура

Содержимое, фальцуемое с применением этой стратегии, должно соответствовать описанной ниже структуре.

7.1.1. Заголовок

Заголовок включает 2 строки. Первая строка содержит приведённую ниже строку из 36 символов, которая может быть окружена любыми печатаемыми символами. Сама эта строка не может быть разделена.

   NOTE: '\' line wrapping per RFC 87923

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

7.1.2. Тело

Кодирование символов совпадает с описанным в разделе 2 [RFC7994], за исключением того, что [RFC7991] запрещает применение символов табуляции.

Строки с символом \ в конце считаются фальцуемыми (разделяемыми).

Очень длинные строки можно делить на множество частей.

7.2. Алгоритм

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

Когда в большом документе неоднократно встречается содержимое, требующее разделения и сборки, другой процесс должен извлечь (или вставить) отдельные блоки с длинными строками до использования описанных здесь алгоритмов. Например, это может делать утилита xiax [xiax].

7.2.1. Разделение

Определяется желаемый размер строки от ввода до процесса разделения (line-wrapping), например из параметра командной строки. Если значение не задано явно, следует использовать размер 69 символов. Желаемый максимум должен быть не меньше размера заголовка, составляющего 36 символов. Если желаемый размер меньше этого значения, процесс завершается (содержимое не фальцуется).

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

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

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

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

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

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

  2. В найденное место строки помещается символ \ и символы завершения строки.

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

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

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

Описанный здесь процесс иллюстрирует функция fold_it_1() в Приложении A.

7.2.2. Сборка

Сканируется начало текстового содержимого в поиске заголовка (7.1.1. Заголовок). При отсутствии заголовка работа завершается (сбора не нужна).

Удаляются две строки заголовка из текстового содержимого.

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

Операции продолжаются до конца текстового содержимого.

Пример процесса показан в функции unfold_it_1() Приложения A.

8. Стратегия Double Backslash (\\)

8.1. Сфальцованная структура

Содержимое, фальцуемое с применением этой стратегии, должно соответствовать описанной ниже структуре.

8.1.1. Заголовок

Заголовок включает 2 строки. Первая строка содержит приведённую ниже строку из 37 символов, которая может быть окружена любыми печатаемыми символами. Сама эта строка не может быть разделена.

   NOTE: '\\' line wrapping per RFC 87924

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

8.1.2. Тело

Кодирование символов совпадает с описанным в разделе 2 [RFC7994], за исключением того, что [RFC7991] запрещает применение символов табуляции.

Строки с символом \ в конце, за которым сразу же следуют символы перевода строки, а следующая строка начинается с символа \, считаются фальцуемыми (разделяемыми).

Очень длинные строки можно делить на множество частей.

8.2. Алгоритм

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

Когда в большом документе неоднократно встречается содержимое, требующее разделения и сборки, другой процесс должен извлечь (или вставить) отдельные блоки с длинными строками до использования описанных здесь алгоритмов. Например, это может делать утилита xiax [xiax].

8.2.1. Разделение

Определяется желаемый размер строки от ввода до процесса разделения (line-wrapping), например из параметра командной строки. Если значение не задано явно, следует использовать размер 69 символов. Желаемый максимум должен быть не меньше размера заголовка, составляющего 37 символов. Если желаемый размер меньше этого значения, процесс завершается (содержимое не фальцуется).

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

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

Сканируется текст в поиске строк, завершающихся символом \, за которой следует строка, начинающаяся с символа \, что могут приводить к неоднозначному результату. Если такая строка найдена и её размер меньше желаемого максимума, строку следует пометить для принудительной (forced) фальцовки (хотя она не требуется). Если реализация не поддерживает принудительную фальцовку, работа должна завершаться.

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

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

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

  2. В найденное место строки помещается символ \ и символы завершения строки.

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

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

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

Описанный здесь процесс иллюстрирует функция fold_it_2() в Приложении A.

8.2.2. Сборка

Сканируется начало текстового содержимого в поиске заголовка (8.1.1. Заголовок). При отсутствии заголовка работа завершается (сбора не нужна).

Удаляются две строки заголовка из текстового содержимого.

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

Операции продолжаются до конца текстового содержимого.

Пример процесса показан в функции unfold_it_2() Приложения A.

9. Примеры

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

9.1. Пример с граничными условиями

Входные данные содержат 7 строк, каждая из которых длиннее предыдущей. Числа служат для удобства учёта. Использовано принятое по умолчанию значение желаемого максимума — 69.

9.1.1. Использование \

   ========== NOTE: '\' line wrapping per RFC 8792 ===========

   123456789012345678901234567890123456789012345678901234567890123456
   1234567890123456789012345678901234567890123456789012345678901234567
   12345678901234567890123456789012345678901234567890123456789012345678
   123456789012345678901234567890123456789012345678901234567890123456789
   12345678901234567890123456789012345678901234567890123456789012345678\
   90
   12345678901234567890123456789012345678901234567890123456789012345678\
   901
   12345678901234567890123456789012345678901234567890123456789012345678\
   9012

9.1.2. Использование \\

   ========== NOTE: '\\' line wrapping per RFC 8792 ==========

   123456789012345678901234567890123456789012345678901234567890123456
   1234567890123456789012345678901234567890123456789012345678901234567
   12345678901234567890123456789012345678901234567890123456789012345678
   123456789012345678901234567890123456789012345678901234567890123456789
   12345678901234567890123456789012345678901234567890123456789012345678\
   \90
   12345678901234567890123456789012345678901234567890123456789012345678\
   \901
   12345678901234567890123456789012345678901234567890123456789012345678\
   \9012

9.2. Пример с несколькими частями одной строки

Этот пример показывает разделение очень длинной строки на несколько частей. Входная строка содержит 280 символов. Числа служат для удобства учёта. Использовано принятое по умолчанию значение желаемого максимума — 69.

9.2.1. Использование \

   ========== NOTE: '\' line wrapping per RFC 8792 ===========

   12345678901234567890123456789012345678901234567890123456789012345678\
   90123456789012345678901234567890123456789012345678901234567890123456\
   78901234567890123456789012345678901234567890123456789012345678901234\
   56789012345678901234567890123456789012345678901234567890123456789012\
   34567890

9.2.2. Использование \\

   ========== NOTE: '\\' line wrapping per RFC 8792 ==========

   12345678901234567890123456789012345678901234567890123456789012345678\
   \9012345678901234567890123456789012345678901234567890123456789012345\
   \6789012345678901234567890123456789012345678901234567890123456789012\
   \3456789012345678901234567890123456789012345678901234567890123456789\
   \01234567890

9.3. Примеры «эффективной» фальцовки

Этот пример показывает улучшение читаемости за счёт «эффективной» фальцовки, которая выполняется в удобных для формата точках. Фальцовка была выполнена вручную, поскольку сценарий из Приложения A не реализует «эффективной» фальцовки. Отметим, что заголовки окружены разными печатаемыми символы, которые не использовались в созданных сценарием примерах.

9.3.1. Использование \

   [NOTE: '\' line wrapping per RFC 8792]
   <yang-library
       xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library"
       xmlns:ds="urn:ietf:params:xml:ns:yang:ietf-datastores">

     <module-set>
       <name>config-modules</name>
       <module>
         <name>ietf-interfaces</name>
         <revision>2018-02-20</revision>
         <namespace>\
           urn:ietf:params:xml:ns:yang:ietf-interfaces\
         </namespace>
       </module>
       ...
     </module-set>
     ...
   </yang-library>

Ниже приведён эквивалентный текст, созданный с использованием сценария из Приложения A.

   ========== NOTE: '\' line wrapping per RFC 8792 ===========
   <yang-library
       xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library"
       xmlns:ds="urn:ietf:params:xml:ns:yang:ietf-datastores">

     <module-set>
       <name>config-modules</name>
       <module>
         <name>ietf-interfaces</name>
         <revision>2018-02-20</revision>
         <namespace>urn:ietf:params:xml:ns:yang:ietf-interfaces</namesp\
   ace>
       </module>
       ...
     </module-set>
     ...
   </yang-library>

9.3.2. Использование \\

[NOTE: '\\' line wrapping per RFC 8792]
   <yang-library
       xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library"
       xmlns:ds="urn:ietf:params:xml:ns:yang:ietf-datastores">

     <module-set>
       <name>config-modules</name>
       <module>
         <name>ietf-interfaces</name>
         <revision>2018-02-20</revision>
         <namespace>\
           \urn:ietf:params:xml:ns:yang:ietf-interfaces\
         \</namespace>
       </module>
       ...
     </module-set>
     ...
   </yang-library>

Ниже приведён эквивалентный текст, созданный с использованием сценария из Приложения A.

   ========== NOTE: '\\' line wrapping per RFC 8792 ==========

   <yang-library
       xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library"
       xmlns:ds="urn:ietf:params:xml:ns:yang:ietf-datastores">

     <module-set>
       <name>config-modules</name>
       <module>
         <name>ietf-interfaces</name>
         <revision>2018-02-20</revision>
         <namespace>urn:ietf:params:xml:ns:yang:ietf-interfaces</namesp\
   \ace>
       </module>
       ...
     </module-set>
     ...
   </yang-library>

9.4. Пример принудительной фальцовки

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

   Следующая строка длиннее 68 символов и её нужно фальцевать.
   123456789012345678901234567890123456789012345678901234567890123456789

   Эта строка завершается символом обратной дробной черты \

   Эта строка завершается символом обратной дробной черты \
   \ Эта строка начинается символом обратной дробной черты

   Эти строки содержат блок символов обратной дробной черты 3x3
      \\\
      \\\
      \\\

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

Отметим, что заголовки содержат символ # вместо знака равенства (=), применённого в примерах выше.

9.4.1. Использование \

# NOTE: '\' line wrapping per RFC 8792
   Следующая строка длиннее 68 символов и её нужно фальцевать.
   1234567890123456789012345678901234567890123456789012345678901234567\
   89

   Эта строка завершается символом обратной дробной черты \\

   Эта строка завершается символом обратной дробной черты \\
   \ Эта строка начинается символом обратной дробной черты

   Эти строки содержат блок символов обратной дробной черты 3x3
      \\\\

      \\\\

      \\\

9.4.2. Использование \\

# NOTE: '\\' line wrapping per RFC 8792
   Следующая строка длиннее 68 символов и её нужно фальцевать.
   1234567890123456789012345678901234567890123456789012345678901234567\
   \89

   Эта строка завершается символом обратной дробной черты \

   Эта строка завершается символом обратной дробной черты \\
   \
   \ Эта строка начинается символом обратной дробной черты

   Эти строки содержат блок символов обратной дробной черты 3x3
      \\\\
      \
      \\\\
      \
      \\\

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

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

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

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

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

12.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>.

[RFC7991] Hoffman, P., «The «xml2rfc» Version 3 Vocabulary», RFC 7991, DOI 10.17487/RFC7991, December 2016, <https://www.rfc-editor.org/info/rfc7991>.

[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>.

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

[bash] «GNU Bash Manual», <https://www.gnu.org/software/bash/manual>.

[pyang] «pyang», <https://pypi.org/project/pyang/>.

[RFC7749] Reschke, J., «The «xml2rfc» Version 2 Vocabulary», RFC 7749, DOI 10.17487/RFC7749, February 2016, <https://www.rfc-editor.org/info/rfc7749>.

[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>.

[RFC7994] Flanagan, H., «Requirements for Plain-Text RFCs», RFC 7994, DOI 10.17487/RFC7994, December 2016, <https://www.rfc-editor.org/info/rfc7994>.

[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>.

[xiax] «The ‘xiax’ Python Package», <https://pypi.org/project/xiax/>.

[xml2rfc] «xml2rfc», <https://pypi.org/project/xml2rfc/>.

[yang-doctors-thread] Watsen, K., «[yang-doctors] automating yang doctor reviews», message to the yang-doctors mailing list, 18 April 2018, <https://mailarchive.ietf.org/arch/msg/yang-doctors/DCfBqgfZPAD7afzeDFlQ1Xm2X3g>.

[yanglint] «yanglint», commit 1b7d73d, February 2020, <https://github.com/CESNET/libyang#yanglint>.

Приложение A. Сценарий bash rfcfold

Это ненормативное прилоежение включает сценарий bash [bash], который может фальцевать и собирать текст с применением обеих стратегий, описанных в разделах 7 и 8. Этот сценарий rfcfold доступен по ссылке <https://github.com/ietf-tools/rfcfold>.

Сценарий предназначен для применения к одному экземпляру текстового содержимого. Если нужно обработать несколько экземпляров текстового содержимого в большом документе (например, Internet-Draft или RFC), нужно использовать другой инструмент для извлечения содержимого из документа перед использованием сценария.

Для удобочитаемости в сценарии принят минимальный размер строки на 8 символов больше размера заголовков, заданных в параграфах 7.1.1 и 8.1.1, чтобы можно было добавить символ пробела ( ) и 3 знака равенства (=) с каждой стороны необработанного заголовка.

При обнаружении во входном файле символа табуляции выдаётся сообщение

      Error: infile contains a tab character, which is not allowed.

Сценарий проверяет доступность GNU awk (gawk) для проверки наличия символов управления ASCII и символов других кодировок (не ASCII) во входном файле (см. ниже). Отметим, что тестирование выявило недостатки применяемой по умолчанию версии awk на некоторых платформах, поэтому сценарий использует лишь gawk и выдаёт предупреждение при недоступности этой утилиты

      Debug: no GNU awk; skipping checks for special characters5.

При доступности gawk и обнаружении во входном файле символов управления ASCII выдаётся предупреждение

      Warning: infile contains ASCII control characters (unsupported).

При доступности gawk и обнаружении во входном файле символов не-ASCII выдаётся предупреждение

      Warning: infile contains non-ASCII characters (unsupported).

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

      Error: infile has a space character occurring on the folding
      column.  This file cannot be folded using the '\' strategy6.

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

Для \

      Error: infile has a line ending with a '\' character.  This file
      cannot be folded using the '\' strategy without there being false
      positives produced in the unfolding (i.e., this script does not
      force-fold such lines, as described in RFC 8792)7.

Для \\

      Error: infile has a line ending with a '\' character followed by a
      '\' character as the first non-space character on the next line.
      This script cannot fold this file using the '\\' strategy without
      there being false positives produced in the unfolding (i.e., this
      script does not force-fold such lines, as described in RFC 8792)8.

Символы \ на уровне оболочки были специально добавлены в сценарий, чтобы он гарантированно не был сфальцован в этом документе и его можно было бы извлечь для применения с помощью операций copy-paste. Поскольку сценарий не содержит обязательного заголовка, описанного в параграфе 7.1.1, эти символы \ не предназначены для фальцовки (например, как описано в разделе 7).

   <CODE BEGINS> file "rfcfold"
   #!/bin/bash --posix

   # Этот сценарий может потребовать действий для работы в конкретной
   # системе. Например, может потребоваться установка утилиты gsed.
   # Также следует обеспечить применение оболочки bash, а не sh.

   # Copyright (c) 2020 IETF Trust, Kent Watsen, and Erik Auerswald.
   # Все права защищены.
   #
   # Распространение и использование в исходной или двоичной форме с
   # изменениями или без таковых разрешено при ряда выполнении условий:
   #
   #   * При распространении в исходном коде должны сохраняться указание
   #     авторских прав, этот список условий и отказ от ответственности.
   #
   #   * При распространении в двоичном коде должны приводиться указание
   #     авторских прав, этот список условий и отказ от ответственности
   #     в документации или ином сопроводительном документе.
   #
   #   * Internet Society, IETF, IETF Trust или имена конкретных
   #     участников работы не могут применяться для поддержки или
   #     продвижения этой программы без соответствующего письменного
   #     разрешения.
   #
   # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   # FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
   # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

   print_usage() {
     printf "\n"
     printf "Folds or unfolds the input text file according to"
     printf " RFC 8792.\n"
     printf "\n"
     printf "Usage: rfcfold [-h] [-d] [-q] [-s <strategy>] [-c <col>]"
     printf " [-r] -i <infile> -o <outfile>\n"
     printf "\n"
     printf "  -s: strategy to use, '1' or '2' (default: try 1,"
     printf " else 2)\n"
     printf "  -c: column to fold on (default: 69)\n"
     printf "  -r: reverses the operation\n"
     printf "  -i: the input filename\n"
     printf "  -o: the output filename\n"
     printf "  -d: show debug messages (unless -q is given)\n"
     printf "  -q: quiet (suppress error and debug messages)\n"
     printf "  -h: show this message\n"
     printf "\n"
     printf "Exit status code: 1 on error, 0 on success, 255 on no-op."
     printf "\n\n"
   }

   # Глобальные переменные, которые не следует менять
   strategy=0 # auto
   debug=0
   quiet=0
   reversed=0
   infile=""
   outfile=""
   maxcol=69  # Принято по умолчанию и может быть задано параметром
   col_gvn=0  # maxcol переопределено?
   hdr_txt_1="NOTE: '\\' line wrapping per RFC 8792"
   hdr_txt_2="NOTE: '\\\\' line wrapping per RFC 8792"
   equal_chars="======================================================="
   space_chars="                                                       "
   temp_dir=""
   prog_name='rfcfold'

   # Функции для диагностических сообщений
   prog_msg() {
     if [[ "$quiet" -eq 0 ]]; then
       format_string="${prog_name}: $1: %s\n"
       shift
       printf -- "$format_string" "$*" >&2
     fi
   }

   err() {
     prog_msg 'Error' "$@"
   }

   warn() {
     prog_msg 'Warning' "$@"
   }

   dbg() {
     if [[ "$debug" -eq 1 ]]; then
       prog_msg 'Debug' "$@"
     fi
   }

   # Определяет имя утилиты [g]sed 
   type gsed > /dev/null 2>&1 && SED=gsed || SED=sed

   # Предупреждение при использовании не-GNU sed
   "$SED" --version < /dev/null 2> /dev/null | grep -q GNU || \
   warn 'not using GNU `sed` (likely cause if an error occurs).'

   cleanup() {
     rm -rf "$temp_dir"
   }
   trap 'cleanup' EXIT

   fold_it_1() {
     # Проверка того, что входной файл уже не был сфальцован
     if [[ -n "$("$SED" -n '/\\$/p' "$infile")" ]]; then
       err "infile '$infile' has a line ending with a '\\' character."\
           "This script cannot fold this file using the '\\' strategy"\
           "without there being false positives produced in the"\
           "unfolding."
       return 1
     fi

     # Точка фальцовки (разделения)
     foldcol=$(expr "$maxcol" - 1) # Для вставленного символа \

     # Проверка наличия символа пробела в точке деления
     grep -q "^\(.\{$foldcol\}\)\{1,\} " "$infile"
     if [[ $? -eq 0 ]]; then
       err "infile '$infile' has a space character occurring on the"\
           "folding column.  This file cannot be folded using the"\
           "'\\' strategy."
       return 1
     fi

     # Центровка текста заголовка
     length=$(expr ${#hdr_txt_1} + 2)
     left_sp=$(expr \( "$maxcol" - "$length" \) / 2)
     right_sp=$(expr "$maxcol" - "$length" - "$left_sp")
     header=$(printf "%.*s %s %.*s" "$left_sp" "$equal_chars"\
                      "$hdr_txt_1" "$right_sp" "$equal_chars")

     # Создание выходного файла
     echo "$header" > "$outfile"
     echo "" >> "$outfile"
     "$SED" 's/\(.\{'"$foldcol"'\}\)\(..\)/\1\\\n\2/;t M;b;:M;P;D;'\
       < "$infile" >> "$outfile" 2> /dev/null
     if [[ $? -ne 0 ]]; then
       return 1
     fi
     return 0
   }

   fold_it_2() {
     # Точка фальцовки (разделения)
     foldcol=$(expr "$maxcol" - 1) # Для вставленного символа \

     # Проверка наличия в файле символов фальцовки (fold-sequence)
     if [[ -n "$("$SED" -n '/\\$/{N;s/\\\n[ ]*\\/&/p;D}' "$infile")" ]]
     then
       err "infile '$infile' has a line ending with a '\\' character"\
           "followed by a '\\' character as the first non-space"\
           "character on the next line.  This script cannot fold"\
           "this file using the '\\\\' strategy without there being"\
           "false positives produced in the unfolding."
       return 1
     fi

     # Центровка текста заголовка
     length=$(expr ${#hdr_txt_2} + 2)
     left_sp=$(expr \( "$maxcol" - "$length" \) / 2)
     right_sp=$(expr "$maxcol" - "$length" - "$left_sp")
     header=$(printf "%.*s %s %.*s" "$left_sp" "$equal_chars"\
                      "$hdr_txt_2" "$right_sp" "$equal_chars")

     # Создание выходного файла
     echo "$header" > "$outfile"
     echo "" >> "$outfile"
     "$SED" 's/\(.\{'"$foldcol"'\}\)\(..\)/\1\\\n\\\2/;t M;b;:M;P;D;'\
       < "$infile" >> "$outfile" 2> /dev/null
     if [[ $? -ne 0 ]]; then
       return 1
     fi
     return 0
   }

   fold_it() {
     # Проверка наличия во входном файле символов табуляции
     grep -q $'\t' "$infile"
     if [[ $? -eq 0 ]]; then
       err "infile '$infile' contains a tab character, which is not"\
           "allowed."
       return 1
     fi

     # Фальцовка строк с символами управления ASCII или кодами не-ASCII
     # может приводить к ошибкам разделения строк и не поддерживается
     if type gawk > /dev/null 2>&1; then
       env LC_ALL=C gawk '/[\000-\014\016-\037\177]/{exit 1}' "$infile"\
       || warn "infile '$infile' contains ASCII control characters"\
               "(unsupported)."
       env LC_ALL=C gawk '/[^\000-\177]/{exit 1}' "$infile"\
       || warn "infile '$infile' contains non-ASCII characters"\
               "(unsupported)."
     else
       dbg "no GNU awk; skipping checks for special characters."
     fi

     # Нужна ли фальцовка файла?
     testcol=$(expr "$maxcol" + 1)
     grep -q ".\{$testcol\}" "$infile"
     if [[ $? -ne 0 ]]; then
       dbg "nothing to do; copying infile to outfile."
       cp "$infile" "$outfile"
       return 255
     fi

     if [[ "$strategy" -eq 1 ]]; then
       fold_it_1
       return $?
     fi
     if [[ "$strategy" -eq 2 ]]; then
       fold_it_2
       return $?
     fi
     quiet_sav="$quiet"
     quiet=1
     fold_it_1
     result=$?
     quiet="$quiet_sav"
     if [[ "$result" -ne 0 ]]; then
       dbg "Folding strategy '1' didn't succeed; trying strategy '2'..."
       fold_it_2
       return $?
     fi
     return 0
   }

   unfold_it_1() {
     temp_dir=$(mktemp -d)

     # Вывод всего, кроме двух первых строк в файл wip
     awk "NR>2" "$infile" > "$temp_dir/wip"

     # Сборка (unfold) файла wip
     "$SED" '{H;$!d};x;s/^\n//;s/\\\n *//g' "$temp_dir/wip" > "$outfile"

     return 0
   }

   unfold_it_2() {
     temp_dir=$(mktemp -d)

     # Вывод всего, кроме двух первых строк в файл wip
     awk "NR>2" "$infile" > "$temp_dir/wip"

     # Сборка (unfold) файла wip
     "$SED" '{H;$!d};x;s/^\n//;s/\\\n *\\//g' "$temp_dir/wip"\
       > "$outfile"

     return 0
   }

   unfold_it() {
     # Нужна ли сборка (unfold) файла?
     line=$(head -n 1 "$infile")
     line2=$("$SED" -n '2p' "$infile")
     result=$(echo "$line" | fgrep "$hdr_txt_1")
     if [[ $? -eq 0 ]]; then
       if [[ -n "$line2" ]]; then
         err "the second line in '$infile' is not empty."
         return 1
       fi
       unfold_it_1
       return $?
     fi
     result=$(echo "$line" | fgrep "$hdr_txt_2")
     if [[ $? -eq 0 ]]; then
       if [[ -n "$line2" ]]; then
         err "the second line in '$infile' is not empty."
         return 1
       fi
       unfold_it_2
       return $?
     fi
     dbg "nothing to do; copying infile to outfile."
     cp "$infile" "$outfile"
     return 255
   }

   process_input() {
     while [[ "$1" != "" ]]; do
       if [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]]; then
         print_usage
         exit 0
       elif [[ "$1" == "-d" ]]; then
         debug=1
       elif [[ "$1" == "-q" ]]; then
         quiet=1
       elif [[ "$1" == "-s" ]]; then
         if [[ "$#" -eq "1" ]]; then
           err "option '-s' needs an argument (use -h for help)."
           exit 1
         fi
         strategy="$2"
         shift
       elif [[ "$1" == "-c" ]]; then
         if [[ "$#" -eq "1" ]]; then
           err "option '-c' needs an argument (use -h for help)."
           exit 1
         fi
         col_gvn=1
         maxcol="$2"
         shift
       elif [[ "$1" == "-r" ]]; then
         reversed=1
       elif [[ "$1" == "-i" ]]; then
         if [[ "$#" -eq "1" ]]; then
           err "option '-i' needs an argument (use -h for help)."
           exit 1
         fi
         infile="$2"
         shift
       elif [[ "$1" == "-o" ]]; then
         if [[ "$#" -eq "1" ]]; then
           err "option '-o' needs an argument (use -h for help)."
           exit 1
         fi
         outfile="$2"
         shift
       else
         warn "ignoring unknown option '$1'."
       fi
       shift
     done

     if [[ -z "$infile" ]]; then
       err "infile parameter missing (use -h for help)."
       exit 1
     fi

     if [[ -z "$outfile" ]]; then
       err "outfile parameter missing (use -h for help)."
       exit 1
     fi

     if [[ ! -f "$infile" ]]; then
       err "specified file '$infile' does not exist."
       exit 1
     fi

     if [[ "$col_gvn" -eq 1 ]] && [[ "$reversed" -eq 1 ]]; then
       warn "'-c' option ignored when unfolding (option '-r')."
     fi

     if [[ "$strategy" -eq 0 ]] || [[ "$strategy" -eq 2 ]]; then
       min_supported=$(expr ${#hdr_txt_2} + 8)
     else
       min_supported=$(expr ${#hdr_txt_1} + 8)
     fi
     if [[ "$maxcol" -lt "$min_supported" ]]; then
       err "the folding column cannot be less than $min_supported."
       exit 1
     fi

     # this is only because the code otherwise runs out of equal_chars
     max_supported=$(expr ${#equal_chars} + 1 + ${#hdr_txt_1} + 1\
          + ${#equal_chars})
     if [[ "$maxcol" -gt "$max_supported" ]]; then
       err "the folding column cannot be more than $max_supported."
       exit 1
     fi
   }

   main() {
     if [[ "$#" -eq "0" ]]; then
        print_usage
        exit 1
     fi

     process_input "$@"

     if [[ "$reversed" -eq 0 ]]; then
       fold_it
       code=$?
     else
       unfold_it
       code=$?
     fi
     exit "$code"
   }

   main "$@"
   <CODE ENDS>

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

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

Спасибо Ben Kaduk, Benoit Claise, Gianmarco Bruno, Italo Busi, Joel Jaeggli, Jonathan Hansford, Lou Berger, Martin Bjorklund, Rob Wilton (по алфавиту) за вклад в подготовку этого документа.

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

Kent Watsen
Watsen Networks
Email: kent+ietf@watsen.net
 
Erik Auerswald
Individual Contributor
Email: auerswal@unix-ag.uni-kl.de
 
Adrian Farrel
Old Dog Consulting
Email: adrian@olddog.co.uk
 
Qin Wu
Huawei Technologies
Email: bill.wu@huawei.com

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

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

nmalykh@protokols.ru

1Internet Engineering Task Force — комиссия по решению инженерных задач Internet.

2Internet Engineering Steering Group — комиссия по инженерным разработкам Internet.

3Разбиение (перенос строки) в соответствии с RFC 8792.

4Разбиение (перенос строки) в соответствии с RFC 8792.

5GNU awk не обнаружено и проверка наличия специальных символов не выполнялась.

6Входной файл содержит пробел в точке разделения и его нельзя обработать с использованием стратегии с одним символом \.

7Входной файл содержит строку, завершающуюся символом \. Такой файл нельзя обработать в стратегии с одним символом \ без ложных срабатываний при последующей сборке (т. е. сценарий не фальцует такие строки принудительно, как указано в RFC 8792).

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

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