RFC 9108 YANG Types for DNS Classes and Resource Record Types

image_print
Internet Engineering Task Force (IETF)                         L. Lhotka
Request for Comments: 9108                                        CZ.NIC
Category: Standards Track                                      P. Špaček
ISSN: 2070-1721                              Internet Systems Consortium
                                                          September 2021

YANG Types for DNS Classes and Resource Record Types

Типы YANG для классов DNS и типов RR

PDF

Аннотация

Этот документ вводит модуль YANG iana-dns-class-rr-type, содержащий производные типы данных, отражающие реестры IANA DNS CLASSes и Resource Record (RR) TYPEs. Эти типы YANG служат начальной основой для будущей работы по моделированию данных.

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

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

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

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

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

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

Оглавление

Исключено в версии HTML

1. Введение

Язык YANG [RFC7950] стал фактическим стандартом моделирования данных конфигурации и состояния, а также задания управляющих операций и асинхронных уведомлений. Разумно ожидать, что основанный на таких моделях данных подход вместе со стандартными протоколами управления, такими как NETCONF [RFC6241] и RESTCONF [RFC8040], можно будет эффективно применять и в операциях DNS. Фактически в настоящее время уже предпринимаются попытки использовать NETCONF и RESTCONF для настройки и управления:

  • полномочными серверами;

  • распознавателями;

  • данными зон.

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

На основе опыта IETF Routing Area можно ожидать, что разработка унифицированных моделей данных для DNS окажется сложной и длительной и потребует активного сотрудничества и компромиссов между разработчиками и поставщиками основных серверных платформ DNS. Тем не менее, вполне вероятно, что любое моделирование относящихся к DNS данных потребует использования различных параметров и перечней DNS, заданных в нескольких реестрах IANA. Для использования с YANG эти параметры и перечни нужно перевести в соответствующие типы YANG или иные структуры. Такой трансляции следует быть простой и сравнительно бесспорной.

Этот документ обеспечивает трансляцию двух связанных с DNS фундаментальных реестров IANA в YANG. Документ содержит первоначальную версию модуля YANG iana-dns-class-rr-type, которая определяет производные типы для общих параметров записей DNS о ресурсах (RR) – класс и тип. Типы YANG dns-class и rr-type, отражают реестры IANA DNS CLASSes и Resource Record (RR) TYPEs [IANA-DNS-PARAMETERS].

В Приложении A приведена таблица стилей XSLT 1.0, предназначенная для использования IANA при генерации исходной версии модуля iana-dns-class-rr-type. Впоследствии при добавлении нового класса или типа RR в упомянутые реестры IANA будет также обновлять модуль iana-dns-class-rr-type, следуя инструкциям раздела 4.

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

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

Терминология для описания моделей данных YANG приведена в [RFC7950]. Используемые в документе термины DNS определены в [RFC1035] и [RFC8499].

3. Вопросы проектирования YANG

Во время написания этого документа реестр «Domain Name System (DNS) Parameters» [IANA-DNS-PARAMETERS] включал 13 субреестров. Модуль YANG iana-dns-class-rr-type определяет производные типы, соответствующие лишь 2 реестрам, которые важны для моделей данных, включающих данные зоны, а именно «DNS CLASSes» и «Resource Record (RR) TYPEs». Предполагается, что оставшиеся реестры [IANA-DNS-PARAMETERS], а также другие реестры IANA, связанные с DNS, по мере необходимости будут отражаться в последующих модулях YANG. Таким образом, можно будет выбрать подходящую комбинацию модулей YANG в зависимости от требуемых типов YANG и целей моделирования.

Реестры «DNS CLASSes» и «Resource Record (RR) TYPEs» преобразованы в перечисляемые типы YANG dns-class-name и rr-type-name, соответственно. Ниже приведён начальный фрагмент первого из них.

     typedef dns-class-name {
       type enumeration {
         enum IN {
           value 1;
           description
             "Internet (IN)";
           reference
             "RFC 1035";
         }
         ...
       }
       ...
     }

Другой производный тип rr-type-name определён аналогичным способом.

В [RFC3597] введена опция для указания класса или типа RR присвоенным ему десятичным номером вместо мнемонического имени. Например, класс IN можно указать как CLASS1, а тип AAAA – как TYPE28. В соответствии с этим производные типы dns-class и rr-type определены в модуле YANG как объединение двух типов:

  • 16-битовое десятичное значение (uint16);

  • мнемоническое имя, относящееся к перечисляемым типам dns-class-name и rr-type-name.

Например, тип rr-type определён как

     typedef rr-type {
       type union {
         type uint16;
         type rr-type-name;
       }
       description
         "Этот тип позволяет указывать тип записи о ресурсе DNS
          с использованием мнемонического имени или числа.";
     }

Поскольку для невыделенных и резервных классов и типов RR нет мнемонических имён, их можно указать лишь числами.

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

В этом разделе рассматриваются действия и процессы IANA, требуемые для поддержки модуля YANG iana-dns-class-rr-type, предназначенного для отображения реестров DNS CLASSes и Resource Record (RR) TYPEs [IANA-DNS-PARAMETERS]. Свежая версия модуля YANG доступна в реестре YANG Parameters [IANA-YANG-PARAMETERS].

С публикацией этого документа агентство IANA создало и разместило начальную версию модуля iana-dns-class-rr-type путём применения таблицы стилей XSLT из Приложения A к XML-версии [IANA-DNS-PARAMETERS].

Ниже приведено примечание, добавленное IANA к записи iana-dns-class-rr-type в реестре YANG Module Names [IANA-YANG-PARAMETERS].

Классы и типы записей о ресурсах DNS недопустимо добавлять напрямую в модуль YANG iana-dns-class-rr-type, они должны добавляться в реестры DNS CLASSes и Resource Record (RR) TYPEs, соответственно.

При добавлении класса DNS или типа RR в реестр DNS CLASSes или Resource Record (RR) TYPEs нужно добавлять оператор enum к типу dns-class-name или rr-type-name, соответственно. Имени в enum нужно совпадать с мнемоническим именем нового класса или типа. В оператор enum нужно включить указанные ниже субоператоры.

value

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

status

Включается лишь для классов или типов, регистрация которых отменена или устарела. Значениям deprecated и obsolete в реестре соответствуют такие же значения в модуле YANG.

description

Копия соответствующих сведений из реестра, а именно полное имя нового класса DNS или значение нового типа RR, если оно имеется.

reference

Копия ссылок из реестра.

Невыделенные и резервные значение не нужно включать в перечисляемые типы dns-class-name и rr-type-name.

При каждом обновлении модуля YANG iana-dns-class-rr-type нужно добавлять новый оператор revision перед имеющимися операторами revision.

Ниже приведено примечание, добавленное IANA в реестры DNS CLASSes и Resource Record (RR) TYPEs.

При изменении реестра должен обновляться модуль YANG iana-dns-class-rr-type, как указано в [RFC9108].

Ниже приведено обновление текста Reference в реестре DNS CLASSes.

Старый текст

[RFC6895]

Новый текст

[RFC6895][RFC9108]

Ниже приведено обновление текста Reference в реестре Resource Record (RR) TYPEs.

Старый текст

[RFC6895][RFC1035]

Новый текст

[RFC6895][RFC1035][RFC9108]

4.1. Регистрация URI

Этот документ регистрирует URI в реестре IETF XML [RFC3688], добавляя в него приведённые ниже записи.

   URI:  urn:ietf:params:xml:ns:yang:iana-dns-class-rr-type
   Registrant Contact:  The IESG.
   XML:  N/A; the requested URI is an XML namespace3.

4.2. Регистрация модуля YANG

Этот документ регистрирует модуль YANG в реестре YANG Module Names [RFC6020], добавляя в него приведённые ниже записи.

   Name:  iana-dns-class-rr-type
   Namespace:  urn:ietf:params:xml:ns:yang:iana-dns-class-rr-type
   Prefix:  dnsct
   Reference:  RFC 9108

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

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

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

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

[IANA-DNS-PARAMETERS] IANA, “Domain Name System (DNS) Parameters”, <https://www.iana.org/assignments/dns-parameters>.

[IANA-YANG-PARAMETERS] IANA, “YANG Parameters”, <https://www.iana.org/assignments/yang-parameters>.

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

[RFC7950] Bjorklund, M., Ed., “The YANG 1.1 Data Modeling Language”, RFC 7950, DOI 10.17487/RFC7950, August 2016, <https://www.rfc-editor.org/info/rfc7950>.

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

[W3C.REC-xslt-19991116] Clark, J., “XSL Transformations (XSLT) Version 1.0”, W3C Recommendation REC-xslt-19991116, November 1999, <https://www.w3.org/TR/1999/REC-xslt-19991116>.

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

[RFC1035] Mockapetris, P., “Domain names – implementation and specification”, STD 13, RFC 1035, DOI 10.17487/RFC1035, November 1987, <https://www.rfc-editor.org/info/rfc1035>.

[RFC3597] Gustafsson, A., “Handling of Unknown DNS Resource Record (RR) Types”, RFC 3597, DOI 10.17487/RFC3597, September 2003, <https://www.rfc-editor.org/info/rfc3597>.

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

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

[RFC8499] Hoffman, P., Sullivan, A., and K. Fujiwara, “DNS Terminology”, BCP 219, RFC 8499, DOI 10.17487/RFC8499, January 2019, <https://www.rfc-editor.org/info/rfc8499>.

Приложение A. Таблица стилей XSLT

В этом приложении содержится таблица стилей XSLT 1.0 [W3C.REC-xslt-19991116], использованная для создания исходной версии модуля YANG iana-dns-class-rr-type. Это было выполнено путём применения таблицы стилей к XML-версии реестра IANA Domain Name System (DNS) Parameters [IANA-DNS-PARAMETERS] на момент публикации этого документа.

С помощью программы xsltproc текст модуля YANG можно создать командой

       $ xsltproc iana-dns-class-rr-type.xsl dns-parameters.xml

   <CODE BEGINS> file "iana-dns-class-rr-type.xsl"
   <?xml version="1.0" standalone="yes"?>
   <stylesheet xmlns="http://www.w3.org/1999/XSL/Transform"
               xmlns:iana="http://www.iana.org/assignments"
               version="1.0">
     <output method="text"/>
     <strip-space elements="*"/>

     <variable name="dq">"</variable>
     <variable name="sq">'</variable>

     <variable name="module-intro">
       <text>module iana-dns-class-rr-type {
     yang-version 1.1;
     namespace
       "urn:ietf:params:xml:ns:yang:iana-dns-class-rr-type";
     prefix dnsct;

     organization
       "Internet Assigned Numbers Authority (IANA)";

     contact
       "        Internet Assigned Numbers Authority

        Postal: ICANN
                12025 Waterfront Drive, Suite 300
                Los Angeles, CA 90094

        Tel:    +1 424 254 5300

        &lt;mailto:iana@iana.org&gt;";

     description4
       "This YANG module translates IANA registries 'DNS CLASSes' and
        'Resource Record (RR) TYPEs' to YANG-derived types.

        Copyright (c) 2021 IETF Trust and the persons identified as
        authors of the code.  All rights reserved.

        Redistribution and use in source and binary forms, with or
        without modification, is permitted pursuant to, and subject to
        the license terms contained in, the Simplified BSD License set
        forth in Section 4.c of the IETF Trust's Legal Provisions
        Relating to IETF Documents
        (https://trustee.ietf.org/license-info).

        This version of this YANG module was generated from
        the corresponding IANA registries using an XSLT stylesheet
        from Appendix A of RFC 9108
        (https://www.rfc-editor.org/info/rfc9108); see the RFC itself
        for full legal notices.";

     reference
       "IANA 'Domain Name System (DNS) Parameters' registry
        https://www.iana.org/assignments/dns-parameters";</text>
        <text>&#xA;&#xA;</text>
     </variable>

     <template name="enum">
       <param name="id"/>
       <value-of select="concat('      enum ', $id)"/>
       <text> {&#xA;        value </text>
       <value-of select="concat(iana:value, ';&#xA;')"/>
       <if test="contains(iana:description, 'OBSOLETE')">
         <text>        status obsolete;&#xA;</text>
       </if>
       <apply-templates select="iana:description"/>
       <variable name="xrefs" select="iana:xref[@type!='note']"/>
       <if test="$xrefs">
         <text>        reference&#xA;          "</text>
         <if test="count($xrefs)&gt;1">- </if>
         <apply-templates select="iana:xref[@type!='note']"/>
       </if>
       <text>      }&#xA;</text>
     </template>

     <template match="/">
       <value-of select="$module-intro"/>
       <apply-templates select="iana:registry[@id='dns-parameters']"/>
       <text>}&#xA;</text>
     </template>

     <template match="iana:registry[@id='dns-parameters']">
       <apply-templates select="iana:updated"/>
       <apply-templates
           select="iana:registry[@id='dns-parameters-2']"/>
       <apply-templates
           select="iana:registry[@id='dns-parameters-4']"/>
     </template>

     <template match="iana:updated">
       <value-of select="concat('  revision ', ., ' {')"/>
       <text>
       description
         "Initial revision.";
       reference
         "RFC 9108: YANG Types for DNS Classes and Resource Record
          Types";
     }

     /* Typedefs */&#xA;&#xA;</text>
     </template>

     <template match="iana:registry[@id='dns-parameters-2']">
       <text>  typedef dns-class-name {&#xA;</text>
       <text>    type enumeration {&#xA;</text>
       <apply-templates
           select="iana:record[not(iana:description='Unassigned' or
                   starts-with(iana:description,'Reserved'))]"
           mode="class"/>
       <text>    }
       description5
         "This enumeration type defines mnemonic names and corresponding
          numeric values of DNS classes.";
       reference
         "RFC 6895: Domain Name System (DNS) IANA Considerations";
     }

     typedef dns-class {
       type union {
         type uint16;
         type dns-class-name;
       }
       description6
         "This type allows reference to a DNS class using either the
          assigned mnemonic name or numeric value.";
     }&#xA;&#xA;</text>
     </template>

     <template match="iana:registry[@id='dns-parameters-4']">
       <text>  typedef rr-type-name {&#xA;</text>
       <text>    type enumeration {&#xA;</text>
       <apply-templates
           select="iana:record[iana:type!='Unassigned' and
                   iana:type!='Private use' and iana:type!='Reserved']"
           mode="rr-type"/>
       <text>    }
       description7
         "This enumeration type defines mnemonic names and corresponding
          numeric values of DNS resource record types.";
       reference
         "- RFC 6895: Domain Name System (DNS) IANA Considerations

          - RFC 1035: Domain names - implementation and specification";
     }

     typedef rr-type {
       type union {
         type uint16;
         type rr-type-name;
       }
       description8
         "This type allows reference to a DNS resource record type
          using either the assigned mnemonic name or numeric value.";
     }&#xA;</text>
     </template>

     <template match="iana:record" mode="class">
       <call-template name="enum">
         <with-param name="id">
           <choose>
             <when test="contains(iana:description,'(')">
               <value-of select="substring-before(substring-after(
                                 iana:description, '('), ')')"/>
             </when>
             <otherwise>
               <value-of
                   select="substring-after(iana:description, ' ')"/>
             </otherwise>
           </choose>
         </with-param>
       </call-template>
     </template>

     <template match="iana:record" mode="rr-type">
       <call-template name="enum">
         <with-param name="id" select="iana:type"/>
       </call-template>
     </template>

     <template match="iana:description">
       <text>        description&#xA;          </text>
       <value-of select="concat($dq, ., $dq, ';&#xA;')"/>
     </template>

     <template match="iana:xref">
       <choose>
         <when test="@type='rfc'">
           <value-of
               select="concat('RFC ', substring-after(@data, 'rfc'))"/>
         </when>
         <when test="@type='person'">
           <apply-templates
               select="/iana:registry/iana:people/iana:person[
                       @id=current()/@data]"/>
         </when>
         <when test="@type='text'">
           <value-of select="translate(., $dq, $sq)"/>
         </when>
         <otherwise>
           <value-of select="@data"/>
         </otherwise>
       </choose>
       <choose>
         <when test="position()=last()">
           <text>";&#xA;</text>
         </when>
         <otherwise>
           <text>&#xA;           - </text>
         </otherwise>
       </choose>
     </template>

     <template match="iana:person">
       <value-of select="concat(iana:name, ' &lt;', iana:uri, '&gt;')"/>
     </template>

   </stylesheet>
   <CODE ENDS>

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

Ladislav Lhotka

CZ.NIC

Czech Republic

Email: ladislav.lhotka@nic.cz

Petr Špaček

Internet Systems Consortium

Czech Republic

Email: pspacek@isc.org


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

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

nmalykh@protokols.ru

1Internet Engineering Task Force.

2Internet Engineering Steering Group.

3Не задано. Запрошенный идентификатор URI является пространством имён XML.

4Этот модуль YANG транслирует реестры IANA «DNS CLASSes» и «Resource Record (RR) TYPEs» в типы YANG.

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

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

Эта версия модуля YANG создана из соответствующих реестров IANA с использованием таблицы стилей XSLT из Приложения A к RFC 9108 (https://www.rfc-editor.org/info/rfc9108). Полная юридическая информация приведена в самом RFC.

5Этот перечисляемый тип определяет мнемонические имена и соответствующие численные значения для классов DNS.

6Этот тип позволяет указывать классы DNS мнемоническим именем или числом.

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

8Этот тип позволяет указывать записи о ресурсах DNS мнемоническим именем или числом.

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

RFC 9063 Host Identity Protocol Architecture

image_print
Internet Engineering Task Force (IETF)                 R. Moskowitz, Ed.
Request for Comments: 9063                                HTT Consulting
Obsoletes: 4423                                                  M. Komu
Category: Informational                                         Ericsson
ISSN: 2070-1721                                                July 2021

Host Identity Protocol Architecture

Архитектура протокола отождествления хостов

PDF

Аннотация

В этом документе описано пространство имён отождествления хостов (Host Identity), которое обеспечивает криптографическое пространство имён для приложений, протокол отождествления хоста (Host Identity Protocol или HIP), размещаемый между сетевым1 и транспортным уровнем, который поддерживает мобильность конечных хостов, многодомность и работу через NAT. В документе рассмотрены основы используемых в настоящее время пространств имён с их преимуществами и недостатками, а также их дополнение пространством HI. Определены роли пространства имён отождествления хостов в протоколах.

Этот документ отменяет RFC 4423 и решает проблемы, отмеченные IESG, в частности, вопрос гибкости шифрования. В разделе 11. Вопросы безопасности рассмотрены меры предотвращения лавинных атак (flooding), применение идентификаторов в списках контроля доступа, слабые типы идентификаторов и доверие при первом применении. Документ включает в себя уроки, извлечённые из реализации RFC 7401, и идёт дальше в разъяснении работы HIP как защищённого сигнального канала.

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

Документ относится к категории информационных и не задаёт стандартов Internet.

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

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

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

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

Документ может содержать материалы из IETF Document или IETF Contribution, опубликованных или публично доступных до 10 ноября 2008 года. Лица, контролирующие авторские права на некоторые из таких документов, могли не предоставить IETF Trust права разрешать внесение изменений в такие документы за рамками процессов IETF Standards. Без получения соответствующего разрешения от лиц, контролирующих авторские права этот документ не может быть изменён вне рамок процесса IETF Standards, не могут также создаваться производные документы за рамками процесса IETF Standards за исключением форматирования документа для публикации или перевода с английского языка на другие языки.

Оглавление

Исключено в варианте HTML.

1. Введение

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

Предлагаемое пространство имён отождествления хостов также является глобальными занимает место между пространствами IP и DNS. Концептуально это пространство имён. относится к вычислительной платформе и такая платформа может иметь несколько идентификаторов (поскольку платформа может по разному идентифицировать себя разным партнёрам). Пространство имён. отождествления хостов состоит из идентификаторов хостов (Host Identifier или HI). Для каждого отождествления применяется в точности один идентификатор HI (хотя могут возникать переходные периоды, например, в момент замены ключей, когда могут быть активны несколько идентификаторов). Хотя далее в тексте обсуждаются некриптографические идентификаторы, архитектура фокусируется на криптографических идентификаторах хостов (HI). В частности, HI является открытым ключом асимметричной пары. Каждое отождествление хоста однозначно указывает один хост, т. е. два хоста не могут иметь совпадающие Host Identity. Если идентификаторы HI совпадают у двух или более вычислительных платформ, эти платформы являются экземплярами распределенного хоста. Идентификатор HI может быть публичным (например, доступным через DNS) или непубликуемым. В клиентских системах будут применяться оба типа HI.

Имеется незначительное но важное различие между отождествлением (Host Identity) и идентификатором (HI). Отождествление указывает абстрактную сущность, которая идентифицируется, а идентификатор – конкретную последовательность битов, используемую в процессе идентификации.

Хотя HI могут применяться во многих системах проверки подлинности (аутентификации), таких как IKEv2 [RFC7296], представленная архитектура задаёт новый протокол, названный протоколом отождествления хоста (Host Identity Protocol или HIP), и криптографический обмен, названный базовым обменом HIP (см. 6. Плоскость управления. HIP обеспечивает ограниченные варианты доверия между системами, повышает уровни мобильности, многодомности и динамической смены адресов IP, помогая в трансляции и изменении протоколов, а также снижая возможности организации некоторых DoS4-атак.

При использовании HIP фактический трафик данных между двумя хостами HIP обычно (но не обязательно) защищается с помощью ESP5 [RFC7402]. Отождествления хостов применяются для создания защищённых связей ESP (Security Association или SA) и аутентификации хостов. При использовании ESP фактические данные пакетов IP не отличаются от передаваемых в обычных пакетах IP с защитой ESP.

С момента публикации [RFC4423] было получено много информации о HIP [RFC6538]. Этот документ расширяет отождествление хоста за пределы первоначального применения для обеспечения связности IP и защиты, с целью предоставления общей защищённой сигнализации между хостами на уровне любого протокола. Сигналы могут организовать защищённую связь между хостами или просто передавать информацию внутри канала.

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

2.1. Общие с другими документами термины

Таблица 1.

Термин

Определение

Public key
Открытый ключ

Открытый ключ асимметричной криптографической пары ключей. Применяется в качестве доступного идентификатора для криптографической проверки подлинности. Открытость в данном случае трактуется в диапазоне от «известно партнёру» до «известно всем».

Private key
Секретный ключ

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

Public key pair
Пара с открытым ключом

Асимметричная пара криптографических ключей, содержащая открытый и секретный ключ. Например, это может быть пара ключей Rivest-Shamir-Adleman (RSA), Digital Signature Algorithm (DSA), Elliptic Curve DSA (ECDSA).

Endpoint
Конечная точка

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

2.2. Термины, относящиеся к документам HIP

Следует отметить, что многие термины в этом документе являются тавтологическими, самоопределяющими или содержащими циклические ссылки на другие термины. Это связано с лаконичностью определений. Более подробные объяснения приведены в тексте документа и базовой спецификации [RFC7401].

Таблица 2.

Термин

Определение

Computing platform
Вычислительная платформа

Элемент, способный к взаимодействию и расчётам, например, компьютер. См. определение Endpoint выше.

HIP base exchange
Базовый обмен HIP

Криптографический протокол (см. также раздел 6).

HIP packet
Пакет HIP

Пакет IP, содержащий сообщение HIP.

Host Identity
Отождествление хоста

Абстрактная концепция, связанная с вычислительной платформе. См. Host Identifier ниже.

Host Identifier
Идентификатор хоста

Открытый ключ, служащий именем для отождествления хоста (Host Identity).

Host Identity namespace
Пространство имён отождествления хостов

Пространство имён, содержащее все возможные HI.

Host Identity Protocol
Протокол отождествления хоста

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

Host Identity Hash
Хэш отождествления хоста

Криптографический хэш, применяемый для создания HIT из HI.

Host Identity Tag
Тег отождествления хоста

128-битовый блок данных, создаваемый применением криптографического хэширования к HI, с битами идентификации метода хэширования.

Local Scope Identifier
Локальный идентификатор

32-битовый блок данных, обозначающий отождествление хоста.

Public Host Identifier and Identity
Публичный идентификатор и отождествление хоста

Опубликованный или общедоступный идентификатор HI, служащий публичным именем для отождествления хоста, и соответствующее отождествление.

Unpublished Host Identifier and Identity
Неопубликованный идентификатор и отождествление хоста

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

Rendezvous Mechanism
Механизм встречи (рандеву)

Механизм, используемый для нахождения мобильных хостов по их HIT.

3. Основы

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

Для этих элементов (платформ) в Internet применяется два основных пространства имён – IP-адреса и доменные имена. Система доменных имён обеспечивает иерархическое выделение имён для некоторых вычислительных платформ и служб. Каждый уровень иерархии получает полномочия от вышележащего уровня и в доменных именах нет анонимности. Примерами доменных имён являются адреса Email, HTTP, SIP.

Пространство адресов IP перегружено их применением для интерфейсов (L3) и конечных точек (связанная с конечной точкой часть L3 и уровень L4). В части именования интерфейсов адреса IP иногда называют «локаторами» (locator) и они служат конечными точками в топологии маршрутизации.

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

В современной сети Internet транспортные уровни неразрывно связаны с адресами IP и не могут развиваться отдельно. На разработку IPng существенно повлиял отказ от создания соответствующего транспорта TCPng.

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

3.1. Пространство имён для вычислительных платформ

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

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

Ниже приведены характеристики пространства имён (для вычислительных платформ) и имён в них.

  • Пространство имён следует применять на уровне «ядра» или стека IP. Стек IP размещается между приложениями и инфраструктурой доставки пакетов.

  • Пространству следует полностью отделять (меж)сетевой уровень от вышележащих уровней. Именам следует заменять собой все вхождения адресов IP внутри приложений (как в блоке управления транспортом Transport Control Block или TCB). Замена может быть выполнена незаметно для унаследованных приложений с помощью локальных идентификаторов (Local Scope Identifier или LSI) и HIT, совместимых с адресами IPv4 и IPv6 [RFC5338]. Однако понимающие HIP приложения потребуется несколько изменить, например, в расширениях API для HIP [RFC6317].

  • Для введения пространства имён не следует требовать какой-либо административной инфраструктуры. Развёртывание должно выполняться снизу вверх попарно.

  • Для имён следует использовать представление фиксированного размера для простоты включения в заголовки дейтаграмм и имеющиеся программные интерфейсы (например, TCB).

  • Пространству имён следует быть доступным при использовании в протоколах. Это связано в основном с размером пакетов, а также вычислениями.

  • По возможности следует избегать конфликтов имён. Можно использовать математический «парадокс дней рождения» для оценки вероятности конфликта в данной популяции и хэш-пространстве. В общем случае для случайного хэш-пространства размером n битов конфликт предполагается после примерно 1,2*sqrt(2n) хэш-значений. Для 64 это составит около 4 миллиардов. Размер 64 бита может оказаться слишком малым для крупных популяций, например вероятность конфликта составит 1% для популяции 640M. Для 100 битов (или более) возникновение конфликта ожидается после расчёта 250 (1 квадриллион) значений. При используемом в настоящее время размере 96 битов [RFC7343] можно рассчитать без конфликтов 248 (281 триллион) значений.

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

  • Должна обеспечиваться возможность локального создания имён. Когда имена не публикуются, это может обеспечивать анонимность за счёт сложности предсказания.

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

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

В этом документе пространство имён, соответствующее приведённым выше характеристикам, называется пространством отождествления хостов – Host Identity. Использование идентификаторов HI требует своего протокольного уровня (Host Identity Protocol) между (меж)сетевым и транспортным уровнем. Имена создаются на основе криптографии с открытым ключом для предоставления услуг аутентификации. При корректной реализации можно обеспечить соответствие всем требованиям, приведённым выше.

4. Пространство имён отождествления хостов

Имя в пространстве Host Identity – идентификатор хоста (HI) представляет статистически уникальное значение для указания любой системы со стеком IP. Это отождествление обычно связано со стеком IP, но не ограничивается такой связью. Система может иметь множество идентификаторов, некоторые могут быть общеизвестными (well known), а другие – анонимными. Система может самостоятельно отождествлять себя или использовать сторонний аутентификатор, например DNSSEC [RFC4033], Pretty Good Privacy (PGP) или X.509 для «нотариального заверения» своего отождествления в другом пространстве имён.

Теоретически, любое имя, статистически уникальное в глобальном масштабе, может служить в качестве HI. В архитектуре HIP в качестве такого имени выбран открытый ключ пары асимметричных ключей, поскольку им можно управлять самостоятельно и такой ключ сложно подделать. Как указано в спецификации протокола HIP [RFC7401], HI на основе открытых ключей позволяет аутентифицировать пакеты HIP и защитить их от MitM6-атак. Поскольку аутентифицированные дейтаграммы обязательны для обеспечения основной защиты HIP от DoS-атак, обмен Diffie-Hellman в базовом обмене HIP использует аутентификацию. Таким образом, на практике поддерживаются лишь HI на базе открытых ключей и аутентифицированные сообщения HIP.

В этом документе упоминаются некриптографические формы HI и HIP, но следует предпочитать криптографические варианты, поскольку они более защищены. В прошлом исследовались варианты применения некриптографических HI для радио-меток (Radio Frequency IDentification или RFID) в обмене HIP, адаптированном для работы с такими задачами ([urien-rfid], [urien-rfid-draft]).

4.1. Идентификаторы хостов

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

Отождествление в HIP основано на парах из секретного и открытого ключа и представляется открытым ключом. Таким образом, имя, представляющее отождествление хоста в пространстве Host Identity, т. е. HI, является открытым ключом. В некотором смысле отождествление определяется владением секретным ключом. Если секретным ключом владеет несколько узлов, отождествление может считаться распределенным.

Архитектурно в качестве HI можно использовать любое другое соглашение от именовании в Internet, однако некриптографичекие имена следует применять лишь в средах с высоким уровнем доверия и/или малыми рисками. Это могут быть места, где не требуется аутентификация (нет риска подмены хоста) или не нужна защита ESP. Однако для соединённых между собой сетей, охватывающих несколько операционных доменов и сред, где существует риск подмены хостов, использование некриптографических HI вносит существенный риск. Поэтому в текущих документах HIP не задано использование HI, не основанных на открытых ключах. Например, служба Back to My Mac [RFC6281] от Apple очень близка по функциональности к HIP, но основана на некриптографических идентификаторах.

Реальные HI не применяются напрямую на транспортном или сетевом уровне. Соответствующие HI (открытые ключи) могут храниться в DNS или иных каталогах, как указано в этом документе, и могут передаваться в базовом обмене HIP. Другие протоколы применяют тег отождествления хоста (Host Identity Tag или HIT) для представления Host Identity. Другое представления отождествлений хостов – локальный идентификатор (Local Scope Identifier или LSI) также можно применять в протоколах и API.

4.2. Хэш отождествления хоста (HIH)

Хэш отождествления хоста (Host Identity Hash или HIH) – это криптографических алгоритм, служащий для создания HIT из HI, а также применяемый в HIP для простоты и единообразия. Два хоста в обмене HIP могут применять разные алгоритмы.

Требуется несколько HIH внутри HIP для решения вопросов создания перемещающихся целей и разрешения возможных конфликтов хэш-значений. Это существенно усложняет протокол HIP и ослабляет возможность атак на понижение в HIP [RFC7401].

4.3. Тег отождествления хоста (HIT)

Тег отождествления хоста (Host Identity Tag или HIT) – это 128-битовое представление Host Identity. Благодаря размеру, тег подходит для использования в имеющихся API сокетов вместо адреса IPv6 (например, sin6_addr в структуре sockaddr_in6) без внесения изменений в приложения. Тег создаётся из HIH, префикса IPv6 [RFC7343] и идентификатора хэш-функции. Имеется два преимущества использования в протоколах HIT вместо HI. Первым является фиксированный размер, что упрощает кодирование протоколов и более эффективное управление размером пакетов. Во-вторых, тег представляет отождествление протоколу в согласованном формате независимо от используемых криптоалгоритмов.

По сути, HIT представляет собой хэш открытого ключа, поэтому не его создание влияют два алгоритма, используемые для открытого ключа HI и HIH. Эти алгоритмы кодируются в битовом представлении HIT. Поскольку две взаимодействующих стороны могут поддерживать разные алгоритмы, в [RFC7401] определён минимальный набор для надёжного взаимодействия. Для расширения возможностей взаимодействия отвечающая сторона (Responder) может сохранять свои ключи в записях DNS и инициатор может связать HIT адресата с соответствующими HIT источника по совпадению HIH.

В пакетах HIP идентификаторы HIT указывают отправителя и получателя пакетов, поэтому значениям HIT следуют быть уникальными во всем пространстве IP, где они применяются. В очень редких случаях, когда одно значение HIT сопоставляется с несколькими Host Identity, идентификаторы HI (открытые ключи) будут обеспечивать различие. Если для данного узла имеется несколько открытых ключей, HIT служит подсказкой для выбора нужного ключа.

Хотя случайные конфликты, когда одно значение HIT сопоставляется с несколькими Host Identity, могут возникать редко, атакующий может с помощью перебора или использования слабости алгоритма, найти второй хэш Host Identity с тем же HIT. Этот тип атак называют атаками на прообраз (preimage attack) и устойчивость к нахождению второго идентификатора HI (открытого ключа), который хэшируется в то же значение HIT называется устойчивостью ко второму прообразу. Такая устойчивость в HIP основана на силе алгоритма хэширования и выходном размере хэш-функции. Для HIPv2 [RFC7401] устойчивость составляет 96 битов (меньше 128-битового размера адреса IPv6 по причине наличия префикса ORCHID7 [RFC7343]). Такая устойчивость сочтена достаточной на момент разработки HIP, но её может не хватить для модели угроз предполагаемого развёртывания. Одним из возможных решений может быть расширение использования HIT в развёртывании за счёт идентификаторов HI (и механизмов защищённой привязки HI к HIT) так, что HI становится окончательным основанием. Можно также усложнить атаки с перебором за счёт увеличения сложности расчёта HI, например, с помощью защищенного обнаружения криптографически созданных адресов соседей (Secure Neighbor Discovery Cryptographically Generated Addres) [RFC3972], хотя спецификации HIP до HIPv2 не предоставляют такого механизма. Если при развёртывании не применяются идентификаторы ORCHID (например, в некоторых типах наложенных сетей), можно использовать полный размер 128 битовых адресов IPv6 для HIT.

4.4. Идентификатор с локальной областью действия (LSI)

LSI – это 32-битовое локализованное представление Host Identity, которое, благодаря его размеру, можно применять в имеющихся API сокетов вместо адресов IPv4 (например, sin_addr в структуре sockaddr_in), не изменяя приложений. Назначение LSI состоит в облегчении использования HI в имеющихся API для приложений IPv4. Значения LSI не передаются в линию и при передаче приложением данных с использованием пары LSI уровень HIP (или обработчик сокетов) транслирует LSI в соответствующие HIT (и обратно в случае приёма данных). Кроме упрощения связности на основе HIP для традиционных приложений IPv4, идентификаторы LSI полезны в 2 других сценариях [RFC6538].

В первом случае два приложения, поддерживающих лишь IPv4, размещены на двух разных хостах, соединённых через сеть с поддержкой только IPv6. Связность на основе HIP позволяет этим приложениям взаимодействовать, несмотря на различие семейств протоколов приложений и базовой сети. Это обусловлено тем, что уровень HIP транслирует LSI от вышележащих уровней в маршрутизируемые локаторы (адреса) IPv6 перед отправкой пакетов в линию.

Второй случай похож на описанный, но одно из приложений поддерживает лишь IPv6. Здесь имеется два препятствия взаимодействию приложений – разные семейства адресов, используемые двумя приложениями, и невозможность приложения IPv4 обмениваться данными с сетью IPv6. Связность на основе HIP решает эту проблему, транслируя локатор (адрес) входящего пакета в LSI или HIT.

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

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

4.5. Сохранение HI в каталогах

Общедоступные HI следует сохранять в DNS, а неопубликованные не следует сохранять нигде, кроме самих взаимодействующих хостов. Для хранения (общедоступных) HI вместе с поддерживаемыми HIH имеется новый тип записи о ресурсах (Resource Record или RR), определённый в расширении HIP DNS [RFC8005].

В дополнение к сохранению HI в DNS их можно хранить в других каталогах, например, LDAP (Lightweight Directory Access Protocol) или PKI (Public Key Infrastructure) [RFC8002]. Кроме того, были успешно использованы [RFC6538] распределенные таблицы хэшей (Distributed Hash Table или DHT) [RFC6537]. Такая практика позволяет применять идентификаторы не только для распознавания хостов.

Некоторые типы приложений могут кэшировать и использовать HI напрямую, а другие опосредованно находить идентификаторы по символьным именам хостов, таким как полные доменные имена (Fully Qualified Domain Name или FQDN), путём просмотра каталогов. Хотя HI могут действовать существенно дольше связанных с ними маршрутизируемых адресов IP, каталоги могут оказаться лучшим подходом для управления сроком действия HI. Например, каталог на основе LDAP или DHT можно применять для опубликованных локально идентификаторов, а DNS лучше подходит для общедоступных.

5. Новая архитектура стека

Одним из способов охарактеризовать Host Identity является сравнение предложенной архитектуры на основе HI с используемой в настоящее время. Как отмечено в отчёте IRTF Name Space Research Group Report [nsrg-report] и, например, документе «Endpoints and Endpoint Names» [chiappa-endpoints], адреса IP в настоящее время играют двойную роль – «локаторов» и идентификаторов конечных точек, т. е. каждый адрес IP указывает топологическое местоположение в Internet, действуя как вектор направления маршрутизации или «локатор», и в то же время именует физический сетевой интерфейс, размещённый в данный момент в точке подключения, выступая как имя конечной точки.

В архитектуре HIP имена конечных точек и «локаторы» отделены одно от другого. Идентификаторы HI указывают конечные точки. Важно понимать, что имена конечных точек, основанные на HI несколько отличаются от имён интерфейсов и доступ к Host Identity может одновременно обеспечиваться через несколько интерфейсов. Различия в привязках логических объектов показаны на рисунке 1, где слева показана текущая архитектура TCP/IP, а справа – архитектура на основе HIP

Транспортная --- Сокет                 Транспортная --- Сокет
ассоциация       |                     ассоциация       |
                 |                                      |
                 |                                      |
                 |                                      |
Конечная         |                     Конечная --- Host Identity
точка    \       |                     точка            |
           \     |                                      |
             \   |                                      |
               \ |                                      |
Место    --- IP-адрес                  Место    --- IP-адрес

Рисунок 1.


Архитектурно HIP обеспечивает разную привязку протоколов транспортного уровня, т. е. ассоциации транспортного уровня (например, соединения TCP и ассоциации UDP) связаны не с адресами IP. А с идентификаторами HI. На практике отождествление хостов раскрывается через LSI и HIT для унаследованных приложений и транспортного уровня, чтобы повысить уровень совместимости с имеющимися сетевыми API и стеками протоколов.

Уровень HIP логически размещён как L3,5 между транспортным и сетевым уровнем сетевого стека и действует как «прокладка», использующая LSI или HIT, но не затрагивающая другие данные. Уровень HIP выполняет преобразование двух форм идентификаторов HIP, приходящих от транспортного уровня, в маршрутизируемые адреса IPv4 или IPv6 для сетевого уровня и обратно.

5.1. Множественное отождествление

Хост может иметь множество отождествлений как на клиентской, так и на серверной стороне. Это вызывает некоторые дополнительные проблемы, рассматриваемые в этом параграфе.

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

На стороне сервера для распределения нагрузки лучше применять DNS, нежели общее отождествление Host Identity. Можно настроить одну запись FQDN указывающую разные Host Identity. Каждую запись FQDN можно связать с соответствующими «локаторами» или общим «локатором», если серверы используют общий сервер HIP rendezvous (6.3. Механизм встречи) или ретранслятор HIP (6.4. Механизм ретрансляции).

Вместо дублирования отождествлений в HIP реализован специальный (opportunistic) режим, в котором инициатор (Initiator) не учитывает идентификатор отвечающего (Responder) при инициировании обмена ключами и узнает его по завершении обмена. Этот компромисс имеет слабые гарантии защиты, но позволяет избежать публикации HI [komu-leap]. Поскольку многие общедоступные серверы уже используют DNS в качестве каталога, такой подход может оказаться более подходящим, например, для соединений «точка-точка». Следует также отметить, что этот режим нужен на практике при использовании в качестве «локаторов» anycast-адресов IP. Этот режим может применяться вместе с серверами HIP rendezvous или ретрансляторами HIP [komu-diss]. В таких случаях инициатор передаёт сообщение I1 с шаблонным HIT адресата «локатору» сервера HIP rendezvous или ретранслятора. Когда такой сервер обслуживает множество зарегистрированных Responder, он может выбирать HIT адресата, выступая балансировщиком на основе HIP. Однако этот подход остаётся экспериментальным и требует дополнительных исследований.

На стороне клиента хост может иметь несколько Host Identity, например, из соображений приватности или при работе пользователя хоста с разными административными доменами в качестве дополнительной меры защиты. Если на пути между клиентом и сервером имеется понимающее HIP промежуточное устройство, например, межсетевой экран (МСЭ) на основе HIP, пользователю или базовой системе следует аккуратно выбирать нужное отождествление, чтобы предотвратить ненужные препятствия со стороны МСЭ на основе HIP [komu-diss].

Сервер также может иметь несколько Host Identity, например, web-сервер может обслуживать несколько административных доменов. Обычно различия реализуются на основе имени DNS, но для этого может служить и Host Identity. Однако более веской причиной использования нескольких отождествлений являются понимающие HIP МСЭ, которые не способны видеть трафик HTTP внутри шифрованных туннелей IPsec. В этом случае для каждой службы можно настроить своё отождествление, позволяя МСЭ разделять службы одного web-сервера [lindqvist-enterprise].

6. Плоскость управления

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

6.1. Базовый обмен

Базовым обменом называется процедура обмена ключами, где Initiator и Responder проверяют подлинность друг друга, используя свои открытые ключи. Обычно инициатором является клиентский хост, а отвечающим (Responder) – сервер. Роли используются конечным автоматом реализации HIP и отбрасываются по завершении.

Обмен включает 4 сообщения и создание симметричных ключей для защиты плоскости управления с помощью хэшированных кодов аутентификации сообщений (Hash-based Message Authentication Code или HMAC). Эти ключи могут также служить для защиты плоскости данных, где обычно применяется IPsec ESP [RFC7402], хотя HIP поддерживает и другие протоколы. Плоскости данных и управления удаляются с помощью процедуры закрытия, включающей 2 сообщения.

Кроме того, базовый обмен включает вычислительную задачу (puzzle) [RFC7401], которую должен решить инициатор. Отвечающий выбирает уровень сложности этой задачи, что позволяет ему задерживать запросы новых инициаторов в соответствии с локальной политикой, например, при высокой нагрузке. Задача-головоломка может обеспечивать некоторую защиту от DoS-атак, поскольку механизм позволяет отвечающему не создавать состояния (stateless) до завершений базового обмена [aura-dos]. Головоломки HIP изучались для установившихся атак DDoS [beal-dos] на множестве моделей злоумышленников с изменением сложности задачи (puzzle) [tritilanunt-dos] и эфемерными отождествлениями хостов [komu-mitigation].

6.2. Мобильные и многоадресные хосты

HIP отделяет транспортный уровень от (меж)сетевого и связывает транспортные ассоциации с отождествлением хоста (через HIT или LSI). После начального обмена ключами уровень HIP поддерживает связность на транспортном уровне и потоки данных с использованием расширений для мобильности [RFC8046] и множественных адресов [RFC8047]. Таким образом, HIP может обеспечить некоторый уровень мобильности и поддержки множественных адресов без больших затрат на инфраструктуру. Поддержка мобильности в HIP включает смену адресов IP (любым способом) у любой из сторон. Система считается мобильной, если её адрес IP может меняться динамически по любой причине, такой как переназначение префикса PPP, DHCP, IPv6 или изменение трансляции NAT. Многодомной (многоадресной) считается система, имеющая одновременно несколько глобально маршрутизируемых адресов IP. HIP связывает адреса IP, если несколько адресов соответствует одному отождествлению хоста. Если один из адресов становится не применимым или появляется более предпочтительный адрес, имеющиеся транспортные ассоциации легко переносятся на другой адрес.

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

6.3. Механизм встречи

Организация контакта с перемещающимся мобильным узлом несколько сложней. Для начала обмена HIP узлу-инициатору нужно узнать, как связаться с мобильным узлом. Например, мобильный узел может реализовать Dynamic DNS [RFC2136] для обновления сведений о своей доступности в DNS. Чтобы избежать зависимости от DNS, в HIP имеется своё решение – механизм встречи HIP rendezvous, определённый в [RFC8004].

С помощью расширений HIP rendezvous мобильный узел постоянно обновляет инфраструктуру встреч, используя текущий адрес(а) IP. Мобильные узлы доверяют механизму встречи HIP для должной поддержки сопоставления их HIT с адресом IP. Механизм встречи особенно полезен в случаях, когда предполагается возможность изменения адресов одновременно обоими партнёрами. В этом случае пакеты HIP UPDATE будут «пересекаться» в сети и не попадут к партнёру.

6.4. Механизм ретрансляции

Механизм ретрансляции HIP [RFC9028] является альтернативой HIP rendezvous и более подходит для сетей IPv4 с NAT, поскольку способен пересылать все коммуникации управления и данных для гарантированного прохождения NAT.

6.5. Завершение плоскости управления

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

7. Плоскость данных

Формат инкапсуляции для плоскости данных, служащей для переноса трафика прикладного уровня, может согласовываться динамически в процессе обмена ключами. Например, расширения HICCUPS [RFC6078] определяют один из способов доставки дейтаграмм прикладного уровня непосредственно через плоскость управления HIP с защитой на основе асимметричных ключей. Защищённый транспорт в реальном масштабе времени (Secure Real-time Transport Protocol или SRTP) также рассматривался в качестве протокола инкапсуляции данных [hip-srtp]. Однако более широкое распространение получил метод инкапсуляции защищённых данных (Encapsulated Security Payload или ESP) [RFC7402], использующий симметричные ключи, выведенные в процессе обмена ключами. Защищённые связи ESP (Security Association или SA) обеспечивают защиту конфиденциальности и целостности, причём первую можно отключить в процессе обмена ключами. В будущем могут быть определены иные способы доставки данных прикладного уровня.

ESP SA организуются и завершаются между инициатором и отвечающим хостом. Обычно хосты создают не менее 2 SA, по одной в каждом направлении (от инициатора к отвечающему и обратно). При смене IP-адреса любого из хостов можно использовать расширение HIP для повторного согласования соответствующих SA.

В линии разница при использовании идентификаторов между плоскостями управления и данных HIP состоит в том, что теги HIT включаются во все пакеты управления, но не включаются в пакеты данных при использовании ESP. Вместо этого применяются индексы параметров защиты ESP (Security Parameter Index или SPI), которые действуют как сжатые HIT. Любым промежуточным устройствам с поддержкой HIP (например, HIP МСЭ), заинтересованным в трафике данных на основе ESP, нужно отслеживать идентификаторы плоскостей данных и управления, чтобы связать их между собой.

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

8. HIP и NAT

Передача пакетов между разными областями адресации IP требует изменения адресов в заголовках пакетов IP. Это может происходить, например, при передаче пакета между Internet и приватным пространством адресов или между сетями IPv4 и IPv6. Трансляция адресов обычно обеспечивается устройствами NAT (Network Address Translation) [RFC3022] или NAT-PT (NAT Protocol Translation) [RFC2766].

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

Расширения для прохождения NAT в протоколе HIP [RFC9028] могут служить для организации сквозной связности через устройства NAT. Для поддержки базовой совместимости с унаследованными устройствами NAT расширения инкапсулируют плоскости управления и данных HIP в протокол UDP. Расширения определяют механизмы для пересылки двух плоскостей через промежуточный хост, называемый ретранслятором HIP (relay) и процедуры для организации прямой сквозной связности через NAT. Поскольку это «естественный» режим прохождения через NAT для HIP, можно использовать и другие механизмы работы через NAT, например, Teredo [RFC4380] (см. [varjonen-split]).

Помимо традиционных NAT была разработана и реализована система NAT с поддержкой протокола HIP [ylitalo-spinat]. Для потоков на основе HIP поддерживающий HIP транслятор NAT или NAT-PT отслеживает сопоставления HIT и соответствующих ESP SPI с адресами IP. Система NAT узнает сопоставления HIT и SPI с адресами IP. Множество HIT (и SPI) может отображаться на один адрес IP в системе NAT, что упрощает соединения на интерфейсах NAT с недостаточным числом адресов. NAT может получать большую часть сведений из самих пакетов HIP, однако может потребоваться некоторая настройка конфигурации NAT.

8.1. HIP и контрольная сумма вышележащего уровня

Хост не может узнать, применялись ли адреса из заголовка IP при расчёте контрольной суммы TCP, т. е. невозможно рассчитать корректную контрольную сумму TCP, используя фактические адреса IP из псевдозаголовка, поскольку адрес в принятом пакете может отличаться от указанного передающим хостом. Кроме того, невозможно пересчитать контрольную сумму вышележащего уровня в системах NAT/NAT-PT, поскольку трафик защищён ESP. Поэтому контрольные суммы TCP и UDP рассчитываются с использованием HIT вместо адресов IP в псевдозаголовке. Используется лишь формат псевдозаголовков IPv6. Это обеспечивает трансляцию протоколов IPv4 и IPv6.

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

Был опубликован ряд исследований групповой адресации на основе HIP, включая [shields-hip], [zhu-hip], [amir-hip], [kovacshazi-host], [zhu-secure]. В частности, так называемые фильтры Блума, позволяющие сжимать несколько меток в небольшие структуры данных, могут быть многообещающим шагом вперёд [sarela-bloom]. Однако разные схемы не были приняты рабочей группой HIP (и исследовательской группой HIP в IRTF), поэтому детали здесь не приведены.

10. Правила HIP

Каждый хост должен поддерживать множество переменных, влияющих на обмен HIP. Всем реализациям HIP следует поддерживать по меньшей мере 2 HI, один из которых публикуется в DNS или иной службе каталогов, а второй не публикуется и служит для анонимного использования (предполагается его частая смена для предотвращения сопоставлений и отслеживания). Хотя неопубликованные HI редко применяются в качестве Responder HI, их часто используют инициаторы. Как указано в [RFC7401], «все реализации HIP должны поддерживать одновременно более одного HI, и по меньшей мере один идентификатор следует резервировать для анонимного использования» и «рекомендуется поддерживать более двух HI». Это ставит перед системами и пользователями вопрос выбора HI, раскрываемого при организации новой сессии.

Специальный (Opportunistic) режим, где инициатор начинает обмен HIP, не зная Responder HI, является компромиссом в части безопасности. Этот режим позволяет инициатору узнать отождествление отвечающего в процессе взаимодействия, а не из внешнего каталога, но это делает его уязвимым для MitM-атак. Этот режим можно применять для регистрации основанных на HIP служб [RFC8003] (т. е. использующих HIP для внутренних целей) или на уровне приложений [komu-leap]. Соображения безопасности, особенно во втором случае, требуют вовлечения пользователя в решение вопроса о восприятии отождествления отвечающего, подобно приглашению в протоколе SSH (Secure Shell) при первом подключении к серверу [pham-leap]. На практике этом может быть реализовано в МСЭ на конечных хостах в случае унаследованных приложений [karvonen-usable] или в естественных API для HIP [RFC6317] в приложениях с поддержкой HIP.

В [RFC7401] сказано: «Инициаторы могут использовать разные HI для разных отвечающих, чтобы обеспечить базовую приватность. Применение таких приватных HI повторно для одного отвечающего и срок действия HI определяется локальными правилами и зависит от требований приватности инициатора». Согласно [RFC7401]: «Responder, отвечающий лишь выбранным инициаторам, требует наличия списка управления доступом (Access Control List или ACL), представляющего хосты, от которых он воспринимает базовый обмен HIP, предпочтительный формат транспорта и локальные сроки действия. Следует поддерживать шаблонные записи в таких ACL, а также для отвечающих, которые предоставляют общедоступные или анонимные услуги.

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

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

11.1. MitM-атаки

Протокол HIP использует парадигму отождествления хоста для защищённой аутентификации хостов и обеспечения быстрого обмена ключами для ESP. HIP также пытается ограничить раскрытие хоста для различных DoS и MitM-атак. При этом сам протокол HIP подвержен атакам DoS и MitM, которые могут нанести большой ущерб работе хоста.

DoS-атаки с истощением ресурсов используют «дороговизну» установки состояния протокола на отвечающей стороне по сравнению с «дешевизной» у инициатора. HIP позволяет отвечающему повысить стоимость запуска состояния на стороне инициатора и пытается снизить расходы отвечающего. Это делается за счёт запуска обмена Diffie-Hellman отвечающим вместо инициатора, что ведёт к базовому обмену HIP из 4 пакетов. Первый пакет, отправленный отвечающим, может быть создан заранее для дополнительного снижения затрат. Этот пакет также включает вычислительную задачу (puzzle), которая может служить для дополнительной задержки инициатора, например, при перегрузке отвечающего. Детали процесса приведены в спецификации базового обмена [RFC7401].

Защититься от MitM-атак сложно без сторонней аутентификации. Опытный атакующий может легко обработать все части базового обмена HIP, но протокол HIP опосредованно обеспечивает дополнительную защиту от MitM-атак. Если значение Responder HI получено из подписанной зоны DNS или иным защищённым способом, инициатор может применить это для аутентификации подписанных пакетов HIP. Если Initiator HI хранится в защищённой зоне DNS, отвечающий может найти идентификатор и проверить подписанные пакеты HIP. Однако инициатор может применять неопубликованный HI, осознанно принимая риск MitM-атаки. Responder может отказаться воспринимать обмен HIP с инициаторами, использующими неизвестный идентификатор HI.

Другие типы MitM-атак на HIP могут быть организованы с использованием сообщений ICMP, сообщающих о проблемах. В качестве общей рекомендации можно указать рассмотрение сообщений ICMP как ненадёжных «советов» и реагирование на них лишь после некоторой паузы (тайм-аут). Точные сценарии атак и меры противодействия описаны более подробно в спецификации базового обмена [RFC7401].

В MitM-атаке может быть предпринята попытка использования старых сообщений I1 или R1 с более слабыми криптографическими алгоритмами, как указано в параграфе 4.1.4 [RFC7401]. Базовый обмен был усилен для борьбы с такими атаками путём перезапуска при обнаружении атаки. В худшем случае это приведёт лишь к бесконечному повтору базового обмена или его прерыванию после некоторого числа попыток. Недостатком этого является 6-этапный базовый обмен, который может показаться неудачным решением. Однако такое возможно лишь при атаке, которая может быть обработана (чтобы повторять её не было смысла), поэтому предполагается, что последующие сообщения не представляют угрозы безопасности. Поскольку MitM-атаки не позволяют снизить версию, их можно считать лишь помехой. Таким образом, базовый обмен будет включать обычно лишь 4 пакета даже при готовности реализации к защите от понижения версии.

В протоколе HIP защищённые связи SA для ESP индексируются по SPI, адрес отправителя всегда игнорируется, а адрес получателя также можно проигнорировать. Поэтому при включённом HIP работа ESP не зависит от адресов IP. Это может показаться упрощением для организации атак, но ESP с защитой от повторного использования (replay) уже обеспечивает высокий уровень безопасности и удаление адреса IP из проверки не увеличивает раскрытие ESP для DoS-атак.

11.2. Защита от лавинных атак

Хотя идея информирования о смене адреса путём простой отправки пакетов с новым адресом источника кажется привлекательной, она недостаточно безопасна. Даже если HIP ни в чем не полагается на адрес отправителя (после завершения базового обмена), представляется необходимой проверка доступности мобильного узла по новому адресу до отправки туда большего объёма данных.

Восприятие новых адресов вслепую (без проверки) открывает возможность для организации лавинных DoS-атак против третьей стороны [RFC4225]. В распределенной лавинной атаке злоумышленник может создать соединения HIP с большим объёмом трафика и множеством хостов (неопубликованные HI) а затем объявить всем этим хостам о своём переходе на другой адрес IP. Если партнерские хосты будут просто воспринимать такой перенос, жертва с указанным адресом может получить лавину пакетов. Для предотвращения таких атак расширения HIP mobility включают процедуру проверки маршрута по обратному пути, где доступность узла проверяется независимо для каждого адреса до отправки по этому адресу большего объёма трафика.

До завершения проверки адреса для передачи данных между хостами можно воспользоваться основанном на кредите подходе «Host Mobility with the Host Identity Protocol» [RFC8046]. При использовании HIP между доверяющими один другому хостами можно отказаться от проверки адресов, однако такое решение следует принимать лишь в случаях, когда узлы заведомо заслуживают доверия и способны защитить себя от вредоносных программ.

11.3. Применение HIT в ACL

На конечных точках теги HIT могут применяться в списках контроля доступа на основе IP для прикладного или сетевого уровня. На промежуточных устройствах понимающие HIP МСЭ [lindqvist-enterprise] могут использовать HIT или открытые ключи для входного или выходного контроля на уровне сети или отдельных хостов даже в присутствии мобильных устройств, поскольку теги HIT и открытые ключи не связаны с топологией. Как отмечено в разделе 7, после организации сессии HIP значение SPI в пакете ESP может служить индексом, указывающим HIT. На практике МСЭ могут проверять пакеты HIP для изучения привязок между HIT, SPI и адресами IP. Можно даже явно контролировать использование ESP, динамически открывая ESP лишь для конкретных SPI и адресов IP. Подписи в пакетах HIP позволяют соответствующему МСЭ гарантировать, что обмен HIP действительно происходит между двумя известными хостами. Это может повысить уровень безопасности МСЭ.

Возможным недостатком HIT в ACL является их «плоская» природа, не позволяющая агрегировать теги, что может приводить к большому размеру таблиц поиска в МСЭ с поддержкой HIP. Способом оптимизации может служить применение фильтров Блума (Bloom) для группировки HIT [sarela-bloom]. Однако следует отметить, что правила для отдельных HIT, а не групп позволяют легко исключить хосты с некорректным поведением, не затрагивая других.

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

Хост может отслеживать всех своих партнёров, которые могут применять его HIT в ACL, регистрируя все удалённые HIT достаточно регистрировать отвечающие хосты). На основе этой информации хост может уведомить другие хосты о смене HIT. Были попытки разработать защищённый метод выдачи уведомлений об отзыве HIT [zhang-revocation].

Некоторые промежуточные устройства с поддержкой HIP, такие как МСЭ [lindqvist-enterprise] или NAT [ylitalo-spinat], могут пассивно просматривать трафик в пути. Такие устройства по своей природе прозрачны и не могут получать уведомлений о переходе хоста в другую сеть. В результате от таких устройств требуется поддержка состояния и тайм-аутов для слишком долгого простоя плоскостей управления и данных между парой конечных хостов HIP. Соответственно, два конечных хоста могут периодически передавать пакеты сохранения (keepalive), такие как UPDATE или сообщения ICMP в туннеле ESP, для поддержки статуса в промежуточном устройстве.

Одним из общих ограничений для сквозного шифрования является неспособность промежуточных устройств участвовать в защите потоков данных. Хотя эта проблема может влиять и на другие протоколы, Heer и др. [heer-end-host] проанализировали её в контексте HIP. В частности, при использовании ESP в качестве протокола плоскости данных для HIP связь между плоскостями данных и управления слаба и может использоваться при некоторых допущениях. Предположим, что злоумышленник получил доступ к целевой сети, защищённой МСЭ с поддержкой HIP, но хочет обойти HIP МСЭ. Для этого атакующий пассивно наблюдает базовый обмен между двумя хостами HIP, а затем воспроизводит его. Таким образом злоумышленнику удаётся преодолеть МСЭ и он может использовать туннель ESP для доставки своих данных. Эта возможность обусловлена тем, что МСЭ не может проверить действительность туннеля ESP. Для решения проблемы промежуточные устройства с поддержкой HIP могут участвовать во взаимодействии с плоскостью управления путём добавления в трафик управления одноразовых параметров (nonce), которые конечные хосты должны подписывать для обеспечения свежести трафика управления [heer-midauth]. Как вариант можно использовать расширения для доставки трафика плоскости данных напрямую через плоскость управления [RFC6078].

11.4. Варианты для HI

В определении идентификатора хоста сказано, что HI не обязательно является открытым ключом. Это означает, что HI может быть любым значением, например, FQDN. Этот документ не описывает поддержку некриптографических HI, но примеры таких вариантов протокола имеются ([urien-rfid], [urien-rfid-draft]). Некриптографические HI по-прежнему будут предоставлять услуги HIT или LSI для прохождения через NAT. Можно переносить теги HIT в пакетах HIP без защиты приватности и конфиденциальности. Такие схемы могут быть пригодны для устройств с ограниченными ресурсами, таких как небольшие датчики с батарейным питанием, но здесь подобные устройства не рассматриваются.

Если желательно использовать HIP в ситуации с низким уровнем защиты, где расчёт открытых ключей считается избыточным, HIP можно применять с очень короткими ключами Diffie-Hellman и Host Identity. Это делает участвующие хосты уязвимыми для MitM-атак и захвата соединений, однако не вызывает опасности лавинных атак, поскольку механизм проверки адресов полагается на систему маршрутизации, а не криптостойкость.

11.5. Доверие при первом применении

В [RFC7435] выделено 4 принципа разработки для принятия на веру (Leap of Faith) или доверия при первом использовании (Trust On First Use или TOFU) для протоколов, применимые также к opportunistic HIP.

  1. Сосуществование с явной политикой.

  2. Приоритизация коммуникаций.

  3. Максимальная защита партнёров.

  4. Отсутствие ложного представления о безопасности.

Согласно первому принципу TOFU: «Защита с использованием обстоятельств (Opportunistic security) никогда не заменит и не вытеснит явные правила.» некоторые данные приложений могут быть слишком конфиденциальными (sensitive), поэтому соответствующая политика может требовать проверки подлинности (т. е. открытого ключа или сертификата) вместо защиты по обстоятельствам без аутентификации. На практике это реализовано в HIP в соответствии с [RFC6538].

OpenHIP позволяет инициатору применять режим Opportunistic лишь с явно заданным IP-адресом отвечающего, когда Responder HIT неизвестен. У отвечающего реализация OpenHIP позволяет включить режим Opportunistic для любого инициатора (доверие к любому инициатору).

Разработчики HIP for Linux (HIPL) экспериментировали с более детализированными правилами на уровне приложения. Реализация HIPL использует так называемую ловушку LD_PRELOAD на уровне приложения, которая позволяет динамически подключаемой библиотеке перехватывать связанные с сокетом вызовы без пересборки соответствующих двоичных файлов приложения. Библиотека выступает промежуточным уровнем между приложениям и транспортом, транслируя не связанные с HIP вызовы сокета из приложения в вызовы на основе HIP. Хотя такая библиотека вносит определённые сложности, описанные в [komu-leap], она достигает цели применения режима Opportunistic на уровне детализации отдельных приложений.

Второй принцип TOFU по сути провозглашает приоритет коммуникаций над безопасностью. Поэтому в общем случае режим Opportunistic следует разрешать даже при отсутствии аутентификации и возможности отката к нешифрованной связи (если правила позволяют) вместо блокировки. На практике это можно реализовать в три этапа. Сначала инициатор HIP может выполнить поиск Responder HI в каталоге (например, DNS). При нахождении инициатором HI он может применить идентификатор для аутентификации и пропустить следующие шаги. При отказе в поиске HI инициатор может попробовать режим Opportunistic с отвечающим. На третьем шаге инициатор может отказаться от коммуникаций на базе HIP после отказа режима Opportunistic, если политика разрешает это. Эта трехступенчатая модель была реализована и описана более подробно в [komu-leap].

Третий принцип TOFU предлагает максимизировать защиту для использования по меньшей мере защиты по обстоятельствам (opportunistic security). Описанная выше трехэтапная модель предпочитает по возможности применять аутентификацию, например, через записи DNS (а при доступности – через DNSSEC) и возвращается в режим Opportunistic при недоступности свидетельств по отдельному каналу (out-of-band credentials). В крайнем случае может происходить отказ от коммуникаций на основе HIP, если правила разрешают это. Поскольку в третьем принципе явно упоминается совершенная защита (perfect forward secrecy или PFS), следует упомянуть её поддержку в HIP.

Четвёртый принцип TOFU гласит, что пользователей и неинтерактивные приложения следует должным образом информировать о применяемом уровне защиты. На практике не поддерживающие HIP приложения будут предполагать отсутствие дополнительной защиты, поэтому ложное представление, по крайней мере у неинтерактивных приложений, возникать не должно. В случае интерактивных desktop-приложений в ранних экспериментах с HIP [karvonen-usable] [RFC6538] использовались приглашения системного уровня для выбора пользователем базовой защиты на основе HIP. Обычно в этих экспериментах пользователи понимали, когда применяется защита на основе HIP. Однако пользователи не замечали разницы между Opportunistic HIP без аутентификации и HIP с аутентификацией но без режима Opportunistic. Причина заключалась в том, что режим Opportunistic HIP (пониженный уровень защиты) не был чётко указан в системном приложении. Это стало уроком в части улучшения пользовательского интерфейса.

В случае понимающих HIP приложений можно использовать естественные API сокетов для HIP, описанные в [RFC6317], для разработки зависящей от приложения логики вместо базового системного приглашения. Здесь приложение само может спросить пользователя или иным способом управлять ситуацией. В этом случае неинтерактивные приложения также могут должным образом осознать уровень защиты, поскольку разработчик может явно задать использование HIP с аутентификацией, Opportunistic HIP или обмен открытыми данными (plain-text).

Следует упомянуть несколько дополнительных пунктов, отмеченных в [RFC7435]. Для активных атак в HIP имеется встроенная защита против понижения версии шифра, как описано в [RFC7401]. Кроме того, могут применяться заранее установленные сертификаты для ослабления атак в случае режима Opportunistic, как отмечено в [RFC6538].

Обнаружение возможностей партнёра также упоминается в контексте TOFU и для этого может применяться трехэтапная модель, отмеченная выше. Хост может выполнить первый этап аутентификации, т. е. обнаружить открытый ключ, например, через DNS. Если хост не находит ключей, он может в качестве второго шага проверить режим Opportunistic. При возникновении тайм-аута хост может перейти к третьему шагу, возвращаясь к взаимодействию без HIP, если политика разрешает это. Последний этап основан на неявном тайм-ауте вместо явного (негативного) подтверждения как в случае DNS, поэтому пользователь может сделать вывод об отказе преждевременно. Для ускорения фазы обнаружения путём явной проверки, поддерживает ли партнёр режим Opportunistic HIP, исследователи предложили расширения для TCP [RFC6538] [komu-leap]. Инициатор передаёт партнёру одновременно пакет (opportunistic) I1 и соответствующую дейтаграмму TCP SYN со специальной опцией TCP. Если партнёр поддерживает HIP, он отбросит пакет SYN и ответит пакетом R1. Если же партнёр не понимает HIP, он отбросит пакет HIP (и неизвестную опцию TCP) и передаст в ответ TCP SYN-ACK. Преимуществом предложенной схемы является быстрый отказ от попытки взаимодействия на основе HIP за один период кругового обхода. Недостаток заключается в привязке к TCP (опции IP также рассматривались, но они плохо работают через МСЭ и NAT). Такой подход не работает против активных атак, но режим Opportunistic в любом случае не предназначен для этого.

Следует отметить, что, несмотря на некоторые преимущества режима Opportunistic, связанные с постепенным развёртыванием, он уступает HIP с аутентификацией [komu-diss], поскольку тот поддерживает постоянные идентификаторы (хост указывается одним HI независимо от перемещений). Opportunistic HIP решает эту задачу лишь частично – после первого контакта между хостами HIP может поддерживать соединение с помощью расширений для мобильности, но возникают проблемы, когда хосты разрывают ассоциацию HIP и пытаются связаться снова. Хост может сменить своё местоположение и нет гарантии привязки адреса IP к хосту, поскольку один адрес может временно выделяться разным хостам (например, сервером DHCP), области адресации могут перекрываться (см. Приложение A.1) или из-за попытки организации атаки.

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

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

13. Отличия от RFC 4423

Отличия от RFC 4423 [RFC4423] являются в основном редакторскими правками, включая разъяснения сложно описанных тем и исключение не относящихся к архитектуре деталей, уже описанных в других документах. Добавлен ряд пропущенных. Включено рассмотрение недостатков HIP, а также безопасности 802.15.4 и MAC, вариантов HIP для IoT, вопросов развёртывания и описание базового обмена.

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

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

[RFC5482] Eggert, L. and F. Gont, “TCP User Timeout Option”, RFC 5482, DOI 10.17487/RFC5482, March 2009, <https://www.rfc-editor.org/info/rfc5482>.

[RFC6079] Camarillo, G., Nikander, P., Hautakorpi, J., Keranen, A., and A. Johnston, “HIP BONE: Host Identity Protocol (HIP) Based Overlay Networking Environment (BONE)”, RFC 6079, DOI 10.17487/RFC6079, January 2011, <https://www.rfc-editor.org/info/rfc6079>.

[RFC7086] Keranen, A., Camarillo, G., and J. Maenpaa, “Host Identity Protocol-Based Overlay Networking Environment (HIP BONE) Instance Specification for REsource LOcation And Discovery (RELOAD)”, RFC 7086, DOI 10.17487/RFC7086, January 2014, <https://www.rfc-editor.org/info/rfc7086>.

[RFC7343] Laganier, J. and F. Dupont, “An IPv6 Prefix for Overlay Routable Cryptographic Hash Identifiers Version 2 (ORCHIDv2)”, RFC 7343, DOI 10.17487/RFC7343, September 2014, <https://www.rfc-editor.org/info/rfc7343>.

[RFC7401] Moskowitz, R., Ed., Heer, T., Jokela, P., and T. Henderson, “Host Identity Protocol Version 2 (HIPv2)”, RFC 7401, DOI 10.17487/RFC7401, April 2015, <https://www.rfc-editor.org/info/rfc7401>.

[RFC7402] Jokela, P., Moskowitz, R., and J. Melen, “Using the Encapsulating Security Payload (ESP) Transport Format with the Host Identity Protocol (HIP)”, RFC 7402, DOI 10.17487/RFC7402, April 2015, <https://www.rfc-editor.org/info/rfc7402>.

[RFC8002] Heer, T. and S. Varjonen, “Host Identity Protocol Certificates”, RFC 8002, DOI 10.17487/RFC8002, October 2016, <https://www.rfc-editor.org/info/rfc8002>.

[RFC8003] Laganier, J. and L. Eggert, “Host Identity Protocol (HIP) Registration Extension”, RFC 8003, DOI 10.17487/RFC8003, October 2016, <https://www.rfc-editor.org/info/rfc8003>.

[RFC8004] Laganier, J. and L. Eggert, “Host Identity Protocol (HIP) Rendezvous Extension”, RFC 8004, DOI 10.17487/RFC8004, October 2016, <https://www.rfc-editor.org/info/rfc8004>.

[RFC8005] Laganier, J., “Host Identity Protocol (HIP) Domain Name System (DNS) Extension”, RFC 8005, DOI 10.17487/RFC8005, October 2016, <https://www.rfc-editor.org/info/rfc8005>.

[RFC8046] Henderson, T., Ed., Vogt, C., and J. Arkko, “Host Mobility with the Host Identity Protocol”, RFC 8046, DOI 10.17487/RFC8046, February 2017, <https://www.rfc-editor.org/info/rfc8046>.

[RFC8047] Henderson, T., Ed., Vogt, C., and J. Arkko, “Host Multihoming with the Host Identity Protocol”, RFC 8047, DOI 10.17487/RFC8047, February 2017, <https://www.rfc-editor.org/info/rfc8047>.

[RFC9028] Keränen, A., Melén, J., and M. Komu, Ed., “Native NAT Traversal Mode for the Host Identity Protocol”, RFC 9028, DOI 10.17487/RFC9028, July 2021, <https://www.rfc-editor.org/info/rfc9028>.

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

[amir-hip] Amir, K., Forsgren, H., Grahn, K., Karvi, T., and G. Pulkkis, “Security and Trust of Public Key Cryptography for HIP and HIP Multicast”, International Journal of Dependable and Trustworthy Information Systems (IJDTIS), Vol. 2, Issue 3, pp. 17-35, DOI 10.4018/jdtis.2011070102, 2013, <https://doi.org/10.4018/jdtis.2011070102>.

[aura-dos] Aura, T., Nikander, P., and J. Leiwo, “DOS-Resistant Authentication with Client Puzzles”, 8th International Workshop on Security Protocols, Security Protocols 2000, Lecture Notes in Computer Science, Vol. 2133, pp. 170-177, Springer, DOI 10.1007/3-540-44810-1_22, September 2001, <https://doi.org/10.1007/3-540-44810-1_22>.

[beal-dos] Beal, J. and T. Shepard, “Deamplification of DoS Attacks via Puzzles”, October 2004.

[camarillo-p2psip] Camarillo, G., Mäenpää, J., Keränen, A., and V. Anderson, “Reducing delays related to NAT traversal in P2PSIP session establishments”, IEEE Consumer Communications and Networking Conference (CCNC), pp. 549-553, DOI 10.1109/CCNC.2011.5766540, 2011, <https://doi.org/10.1109/CCNC.2011.5766540>.

[chiappa-endpoints] Chiappa, J., “Endpoints and Endpoint Names: A Proposed Enhancement to the Internet Architecture”, 1999, <http://mercury.lcs.mit.edu/~jnc/tech/endpoints.txt>.

[heer-end-host] Heer, T., Hummen, R., Komu, M., Gotz, S., and K. Wehrle, “End-Host Authentication and Authorization for Middleboxes Based on a Cryptographic Namespace”, 2009 IEEE International Conference on Communications, DOI 10.1109/ICC.2009.5198984, 2009, <https://doi.org/10.1109/ICC.2009.5198984>.

[heer-midauth] Heer, T., Ed., Hummen, R., Wehrle, K., and M. Komu, “End-Host Authentication for HIP Middleboxes”, Work in Progress, Internet-Draft, draft-heer-hip-middle-auth-04, 31 October 2011, <https://datatracker.ietf.org/doc/html/draft-heer-hip-middle-auth-04>.

[henderson-vpls] Henderson, T. R., Venema, S. C., and D. Mattes, “HIP-based Virtual Private LAN Service (HIPLS)”, Work in Progress, Internet-Draft, draft-henderson-hip-vpls-11, 3 August 2016, <https://datatracker.ietf.org/doc/html/draft-henderson-hip-vpls-11>.

[hip-dex] Moskowitz, R., Ed., Hummen, R., and M. Komu, “HIP Diet EXchange (DEX)”, Work in Progress, Internet-Draft, draft-ietf-hip-dex-24, 19 January 2021, <https://datatracker.ietf.org/doc/html/draft-ietf-hip-dex-24>.

[hip-lte] Liyanage, M., Kumar, P., Ylianttila, M., and A. Gurtov, “Novel secure VPN architectures for LTE backhaul networks”, Security and Communication Networks, Vol. 9, pp. 1198-1215, DOI 10.1002/sec.1411, January 2016, <https://doi.org/10.1002/sec.1411>.

[hip-srtp] Tschofenig, H., Shanmugam, M., and F. Muenz, “Using SRTP transport format with HIP”, Work in Progress, Internet-Draft, draft-tschofenig-hiprg-hip-srtp-02, 25 October 2006, <https://datatracker.ietf.org/doc/html/draft-tschofenig-hiprg-hip-srtp-02>.

[hummen] Hummen, R., Hiller, J., Henze, M., and K. Wehrle, “Slimfit – A HIP DEX compression layer for the IP-based Internet of Things”, 2013 IEEE 9th International Conference on Wireless and Mobile Computing, Networking and Communications (WiMob), pp. 259-266, DOI 10.1109/WiMOB.2013.6673370, October 2013, <https://doi.org/10.1109/WiMOB.2013.6673370>.

[IEEE.802.15.4] IEEE, “IEEE Standard for Low-Rate Wireless Networks”, IEEE Standard 802.15.4, DOI 10.1109/IEEESTD.2020.9144691, July 2020, <https://ieeexplore.ieee.org/document/9144691>.

[IEEE.802.15.9] IEEE, “IEEE Draft Recommended Practice for Transport of Key Management Protocol (KMP) Datagrams”, IEEE P802.15.9/D04, May 2015.

[karvonen-usable] Karvonen, K., Komu, M., and A. Gurtov, “Usable security management with host identity protocol”, 2009 IEEE/ACS International Conference on Computer Systems and Applications, pp. 279-286, DOI 10.1109/AICCSA.2009.5069337, 2009, <https://doi.org/10.1109/AICCSA.2009.5069337>.

[komu-cloud] Komu, M., Sethi, M., Mallavarapu, R., Oirola, H., Khan, R., and S. Tarkoma, “Secure Networking for Virtual Machines in the Cloud”, 2012 IEEE International Conference on Cluster Computing Workshops, pp. 88-96, DOI 10.1109/ClusterW.2012.29, 2012, <https://doi.org/10.1109/ClusterW.2012.29>.

[komu-diss] Komu, M., “A Consolidated Namespace for Network Applications, Developers, Administrators and Users”, Dissertation, Aalto University, Espoo, Finland, ISBN 978-952-60-4904-5 (printed), ISBN 978-952-60-4905-2 (electronic), December 2012.

[komu-leap] Komu, M. and J. Lindqvist, “Leap-of-Faith Security is Enough for IP Mobility”, 2009 6th IEEE Consumer Communications and Networking Conference, Las Vegas, NV, USA, pp. 1-5, DOI 10.1109/CCNC.2009.4784729, January 2009, <https://doi.org/10.1109/CCNC.2009.4784729>.

[komu-mitigation] Komu, M., Tarkoma, S., and A. Lukyanenko, “Mitigation of Unsolicited Traffic Across Domains with Host Identities and Puzzles”, 15th Nordic Conference on Secure IT Systems, NordSec 2010, Lecture Notes in Computer Science, Vol. 7127, pp. 33-48, Springer, ISBN 978-3-642-27936-2, DOI 10.1007/978-3-642-27937-9_3, October 2010, <https://doi.org/10.1007/978-3-642-27937-9_3>.

[kovacshazi-host] Kovacshazi, Z. and R. Vida, “Host Identity Specific Multicast”, International Conference on Networking and Services (ICNS ’07), Athens, Greece, pp. 1-1, DOI 10.1109/ICNS.2007.66, 2007, <https://doi.org/10.1109/ICNS.2007.66>.

[levae-barriers] Levä, T., Komu, M., and S. Luukkainen, “Adoption barriers of network layer protocols: the case of host identity protocol”, Computer Networks, Vol. 57, Issue 10, pp. 2218-2232, ISSN 1389-1286, DOI 10.1016/j.comnet.2012.11.024, March 2013, <https://doi.org/10.1016/j.comnet.2012.11.024>.

[lindqvist-enterprise] Lindqvist, J., Vehmersalo, E., Komu, M., and J. Manner, “Enterprise Network Packet Filtering for Mobile Cryptographic Identities”, International Journal of Handheld Computing Research (IJHCR), Vol. 1, Issue 1, pp. 79-94, DOI 10.4018/jhcr.2010090905, 2010, <https://doi.org/10.4018/jhcr.2010090905>.

[Nik2001] Nikander, P., “Denial-of-Service, Address Ownership, and Early Authentication in the IPv6 World”, 9th International Workshop on Security Protocols, Security Protocols 2001, Lecture Notes in Computer Science, Vol. 2467, pp. 12-21, Springer, DOI 10.1007/3-540-45807-7_3, 2002, <https://doi.org/10.1007/3-540-45807-7_3>.

[nsrg-report] Lear, E. and R. Droms, “What’s In A Name: Thoughts from the NSRG”, Work in Progress, Internet-Draft, draft-irtf-nsrg-report-10, 22 September 2003, <https://datatracker.ietf.org/doc/html/draft-irtf-nsrg-report-10>.

[paine-hip] Paine, R. H., “Beyond HIP: The End to Hacking As We Know It”, BookSurge Publishing, ISBN-10 1439256047, ISBN-13 978-1439256046, 2009.

[pham-leap] Pham, V. and T. Aura, “Security Analysis of Leap-of-Faith Protocols”, 7th International ICST Conference, Security and Privacy for Communication Networks, SecureComm 2011, Lecture Notes of the Institute for Computer Sciences, Social Informatics and Telecommunications Engineering, Vol. 96, DOI 10.1007/978-3-642-31909-9_19, 2012, <https://doi.org/10.1007/978-3-642-31909-9_19>.

[ranjbar-synaptic] Ranjbar, A., Komu, M., Salmela, P., and T. Aura, “SynAPTIC: Secure and Persistent Connectivity for Containers”, 2017 17th IEEE/ACM International Symposium on Cluster, Cloud and Grid Computing (CCGRID), Madrid, 2017, pp. 262-267, DOI 10.1109/CCGRID.2017.62, 2017, <https://doi.org/10.1109/CCGRID.2017.62>.

[RFC2136] Vixie, P., Ed., Thomson, S., Rekhter, Y., and J. Bound, “Dynamic Updates in the Domain Name System (DNS UPDATE)”, RFC 2136, DOI 10.17487/RFC2136, April 1997, <https://www.rfc-editor.org/info/rfc2136>.

[RFC2766] Tsirtsis, G. and P. Srisuresh, “Network Address Translation – Protocol Translation (NAT-PT)”, RFC 2766, DOI 10.17487/RFC2766, February 2000, <https://www.rfc-editor.org/info/rfc2766>.

[RFC3022] Srisuresh, P. and K. Egevang, “Traditional IP Network Address Translator (Traditional NAT)”, RFC 3022, DOI 10.17487/RFC3022, January 2001, <https://www.rfc-editor.org/info/rfc3022>.

[RFC3102] Borella, M., Lo, J., Grabelsky, D., and G. Montenegro, “Realm Specific IP: Framework”, RFC 3102, DOI 10.17487/RFC3102, October 2001, <https://www.rfc-editor.org/info/rfc3102>.

[RFC3748] Aboba, B., Blunk, L., Vollbrecht, J., Carlson, J., and H. Levkowetz, Ed., “Extensible Authentication Protocol (EAP)”, RFC 3748, DOI 10.17487/RFC3748, June 2004, <https://www.rfc-editor.org/info/rfc3748>.

[RFC3972] Aura, T., “Cryptographically Generated Addresses (CGA)”, RFC 3972, DOI 10.17487/RFC3972, March 2005, <https://www.rfc-editor.org/info/rfc3972>.

[RFC4033] Arends, R., Austein, R., Larson, M., Massey, D., and S. Rose, “DNS Security Introduction and Requirements”, RFC 4033, DOI 10.17487/RFC4033, March 2005, <https://www.rfc-editor.org/info/rfc4033>.

[RFC4225] Nikander, P., Arkko, J., Aura, T., Montenegro, G., and E. Nordmark, “Mobile IP Version 6 Route Optimization Security Design Background”, RFC 4225, DOI 10.17487/RFC4225, December 2005, <https://www.rfc-editor.org/info/rfc4225>.

[RFC4380] Huitema, C., “Teredo: Tunneling IPv6 over UDP through Network Address Translations (NATs)”, RFC 4380, DOI 10.17487/RFC4380, February 2006, <https://www.rfc-editor.org/info/rfc4380>.

[RFC4423] Moskowitz, R. and P. Nikander, “Host Identity Protocol (HIP) Architecture”, RFC 4423, DOI 10.17487/RFC4423, May 2006, <https://www.rfc-editor.org/info/rfc4423>.

[RFC5218] Thaler, D. and B. Aboba, “What Makes for a Successful Protocol?”, RFC 5218, DOI 10.17487/RFC5218, July 2008, <https://www.rfc-editor.org/info/rfc5218>.

[RFC5338] Henderson, T., Nikander, P., and M. Komu, “Using the Host Identity Protocol with Legacy Applications”, RFC 5338, DOI 10.17487/RFC5338, September 2008, <https://www.rfc-editor.org/info/rfc5338>.

[RFC5887] Carpenter, B., Atkinson, R., and H. Flinck, “Renumbering Still Needs Work”, RFC 5887, DOI 10.17487/RFC5887, May 2010, <https://www.rfc-editor.org/info/rfc5887>.

[RFC6078] Camarillo, G. and J. Melen, “Host Identity Protocol (HIP) Immediate Carriage and Conveyance of Upper-Layer Protocol Signaling (HICCUPS)”, RFC 6078, DOI 10.17487/RFC6078, January 2011, <https://www.rfc-editor.org/info/rfc6078>.

[RFC6250] Thaler, D., “Evolution of the IP Model”, RFC 6250, DOI 10.17487/RFC6250, May 2011, <https://www.rfc-editor.org/info/rfc6250>.

[RFC6281] Cheshire, S., Zhu, Z., Wakikawa, R., and L. Zhang, “Understanding Apple’s Back to My Mac (BTMM) Service”, RFC 6281, DOI 10.17487/RFC6281, June 2011, <https://www.rfc-editor.org/info/rfc6281>.

[RFC6317] Komu, M. and T. Henderson, “Basic Socket Interface Extensions for the Host Identity Protocol (HIP)”, RFC 6317, DOI 10.17487/RFC6317, July 2011, <https://www.rfc-editor.org/info/rfc6317>.

[RFC6537] Ahrenholz, J., “Host Identity Protocol Distributed Hash Table Interface”, RFC 6537, DOI 10.17487/RFC6537, February 2012, <https://www.rfc-editor.org/info/rfc6537>.

[RFC6538] Henderson, T. and A. Gurtov, “The Host Identity Protocol (HIP) Experiment Report”, RFC 6538, DOI 10.17487/RFC6538, March 2012, <https://www.rfc-editor.org/info/rfc6538>.

[RFC7296] Kaufman, C., Hoffman, P., Nir, Y., Eronen, P., and T. Kivinen, “Internet Key Exchange Protocol Version 2 (IKEv2)”, STD 79, RFC 7296, DOI 10.17487/RFC7296, October 2014, <https://www.rfc-editor.org/info/rfc7296>.

[RFC7435] Dukhovni, V., “Opportunistic Security: Some Protection Most of the Time”, RFC 7435, DOI 10.17487/RFC7435, December 2014, <https://www.rfc-editor.org/info/rfc7435>.

[sarela-bloom] Särelä, M., Esteve Rothenberg, C., Zahemszky, A., Nikander, P., and J. Ott, “BloomCasting: Security in Bloom Filter Based Multicast”, Information Security Technology for Applications, NordSec 2010, Lecture Notes in Computer Science, Vol. 7127, pages 1-16, Springer, DOI 10.1007/978-3-642-27937-9_1, 2012, <https://doi.org/10.1007/978-3-642-27937-9_1>.

[schuetz-intermittent] Schütz, S., Eggert, L., Schmid, S., and M. Brunner, “Protocol enhancements for intermittently connected hosts”, ACM SIGCOMM Computer Communication Review, Vol. 35, Issue 3, pp. 5-18, DOI 10.1145/1070873.1070875, July 2005, <https://doi.org/10.1145/1070873.1070875>.

[shields-hip] Shields, C. and J. J. Garcia-Luna-Aceves, “The HIP protocol for hierarchical multicast routing”, Proceedings of the seventeenth annual ACM symposium on Principles of distributed computing, pp. 257-266, ISBN 0-89791-977-7, DOI 10.1145/277697.277744, 1998, <https://doi.org/10.1145/277697.277744>.

[tempered-networks] Tempered Networks, “Identity-Defined Network (IDN) Architecture: Unified, Secure Networking Made Simple”, White Paper, 2016.

[tritilanunt-dos] Tritilanunt, S., Boyd, C., Foo, E., and J.M.G. Nieto, “Examining the DoS Resistance of HIP”, On the Move to Meaningful Internet Systems 2006: OTM 2006 Workshops, Lecture Notes in Computer Science, Vol. 4277, pp. 616-625, Springer, DOI 10.1007/11915034_85, 2006, <https://doi.org/10.1007/11915034_85>.

[urien-rfid] Urien, P., Chabanne, H., Pepin, C., Orga, S., Bouet, M., de Cunha, D.O., Guyot, V., Pujolle, G., Paradinas, P., Gressier, E., and J.-F. Susini, “HIP-based RFID Networking Architecture”, 2007 IFIP International Conference on Wireless and Optical Communications Networks, pp. 1-5, DOI 10.1109/WOCN.2007.4284140, 2007, <https://doi.org/10.1109/WOCN.2007.4284140>.

[urien-rfid-draft] Urien, P., Lee, G. M., and G. Pujolle, “HIP support for RFIDs”, Work in Progress, Internet-Draft, draft-irtf-hiprg-rfid-07, 23 April 2013, <https://datatracker.ietf.org/doc/html/draft-irtf-hiprg-rfid-07>.

[varjonen-split] Varjonen, S., Komu, M., and A. Gurtov, “Secure and Efficient IPv4/IPv6 Handovers Using Host-Based Identifier-Location Split”, Journal of Communications Software and Systems, Vol. 6, Issue 1, ISSN 18456421, DOI 10.24138/jcomss.v6i1.193, 2010, <https://doi.org/10.24138/jcomss.v6i1.193>.

[xin-hip-lib] Xin, G., “Host Identity Protocol Version 2.5”, Master’s Thesis, Aalto University, Espoo, Finland, June 2012.

[ylitalo-diss] Ylitalo, J., “Secure Mobility at Multiple Granularity Levels over Heterogeneous Datacom Networks”, Dissertation, Helsinki University of Technology, Espoo, Finland, ISBN 978-951-22-9531-9, 2008.

[ylitalo-spinat] Ylitalo, J., Salmela, P., and H. Tschofenig, “SPINAT: Integrating IPsec into Overlay Routing”, First International Conference on Security and Privacy for Emerging Areas in Communication Networks, SECURECOMM’05, Athens, Greece, pp. 315-326, ISBN 0-7695-2369-2, DOI 10.1109/SECURECOMM.2005.53, 2005, <https://doi.org/10.1109/SECURECOMM.2005.53>.

[zhang-revocation] Zhang, D., Kuptsov, D., and S. Shen, “Host Identifier Revocation in HIP”, Work in Progress, Internet-Draft, draft-irtf-hiprg-revocation-05, 9 March 2012, <https://datatracker.ietf.org/doc/html/draft-irtf-hiprg-revocation-05>.

[zhu-hip] Zhu, X., Ding, Z., and X. Wang, “A Multicast Routing Algorithm Applied to HIP-Multicast Model”, 2011 International Conference on Network Computing and Information Security, Guilin, China, pp. 169-174, DOI 10.1109/NCIS.2011.42, 2011, <https://doi.org/10.1109/NCIS.2011.42>.

[zhu-secure] Zhu, X. and J. W. Atwood, “A Secure Multicast Model for Peer-to-Peer and Access Networks Using the Host Identity Protocol”, 2007 4th IEEE Consumer Communications and Networking Conference, Las Vegas, NV, USA, pages 1098-1102, DOI 10.1109/CCNC.2007.221, 2007, <https://doi.org/10.1109/CCNC.2007.221>.

Приложение A. Соображения по устройству

A.1. Преимущества HIP

Изначально протокол сетевого уровня (IP) имел 4 «классических» инварианта:

  1. неизменность – переданный адрес совпадал с принятым;

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

  3. обратимость – адрес возврата всегда определялся перестановкой адресов отправителя и получателя;

  4. всеведение – каждый хост знал, какой адрес можно использовать для передачи пакетов партнёру.

Четвёртый инвариант можно вывести из 1 и 3, но он упомянут явно по причинам, рассмотренным ниже.

В современном «постклассическом» мире предпринимаются попытки исключить п. 2 (для мобильности и применения нескольких адресов), а также произошёл отказ от пп. 1 и 4. Попыткой сохранить п. 4 без п. 1, был документ Realm Specific IP [RFC3102], а IPv6 пытается восстановить п. 1.

Значимые имена DNS имеют немногие клиентские системы в Internet. Т. е. при наличии у клиентской системы имени FQDN это имя обычно относится к устройству NAT или серверу доступа (dial-up), а не указывает реально подключающуюся систему. FQDN (и их расширения в форме почтовых адресов) относятся к уровню приложений (чаще именуются службы, а не отдельные системы). Поэтому многие системы в Internet не зарегистрированы в DNS – у них просто нет служб, интересных другим хостам Internet.

Имена DNS являются ссылками на адреса IP и это лишь демонстрирует связь между сетевым и прикладным уровнем. DNS, как единственная и распределенная база данных Internet, является также хранилищем для других пространств имён, отчасти благодаря DNSSEC и записям ключей для приложений. Хотя каждое пространство имён можно растянуть (IP с помощью v6, DNS с помощью записей KEY), ни одно из них не может адекватно обеспечить аутентификацию хостов или послужить разделом между прикладным и сетевым уровнем.

Пространство имён HI заполняет важный пробел между пространствами IP и DNS. Интересным в HI является возможность отказа хоста от всего, кроме п. 3 для сетевого уровня. Иными словами, пока адреса отправителя и получателя в протоколе сетевого уровня обратимы, HIP заботится об идентификации хоста, а обратимость позволяет локальному хосту получать пакеты от удалённого. Смена адресов в результате прохождения через NAT (изменяемость) или перемещения хоста (мобильность и отсутствие всеведения) может обрабатываться уровнем HIP.

За исключением высокопроизводительных расчётных приложений, API сокетов являются наиболее общим вариантом разработки сетевых приложений, которые используют API напрямую или опосредованно через те или иные библиотеки или модели. Однако API сокетов основаны на допущении о статических адресах IP, а DNS со сроками действия записей придумали позже в процессе развития Internet. Поэтому API сокетов не работают со сроками действия адресов [RFC6250]. Сегодня большая часть пользовательского оборудования стала мобильной, а его адреса эфемерными, но API сокетов по-прежнему создают иллюзию постоянства адресов IP для неосторожных разработчиков. Протокол HIP может служить для укрепления этой иллюзии, поскольку HIP обеспечивает постоянные суррогатные адреса в форме LSI и HIT.

Постоянные идентификаторы, предоставляемые HIP, полезны во многих случаях (см. [ylitalo-diss] [komu-diss]).

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

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

  • При размещении хостов в разных сетях с приватными адресами приложение может однозначно распознавать хосты по их идентификаторам. Иными словами, HIP улучшает прозрачность Internet для уровня приложений [komu-diss].

  • При смене адресов сайта для служб в результате раздела или слияния компаний, а также при смене Internet-провайдера может полностью измениться сетевой префикс организации, что может создавать проблемы для трафика из-за жёсткого задания адресов в файлах конфигурации служб или кэширования адресов IP на стороне клиентов [RFC5887]. С учётом возможных человеческих ошибок использование независимых от местоположения идентификаторов, предоставляемых HIP, может смягчить проблему смены адресов.

  • Может быть повышена гибкость взаимодействия с IPv6, как отмечено в параграфе 4.4. Приложения на основе IPv6 могут взаимодействовать с помощью HIT с приложениями IPv4, использующими идентификаторы LSI. Кроме того, семейство адресов в приложении становится независимым от типа базовой сети (IPv4 или IPv6).

  • Можно применять HIT (или LSI) в списках доступа на основе IP как более защищённую замену адресов IPv6. Помимо защиты, контроль доступа на основе HIT обеспечивает два других преимущества. Во-первых, применение HIT может вдвое сократить размер списков, поскольку не будут нужны отдельные правила для IPv4 [komu-diss]. Во-вторых, правила конфигурации на основе HIT в промежуточных устройствах с поддержкой HIP остаются статическими и не зависят от смены топологии, что упрощает администрирование, особенно для сред с мобильными устройствами. Например, преимущества списков управления доступом на основе HIT применимы в HIP МСЭ, но могут использоваться также непосредственно на конечных хостах [RFC6538].

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

HIP можно объединять с разными протоколами, но сложность получаемых в результате программ может существенно возрасти, а взаимодействие между разными (возможно многоуровневыми) протоколами может негативно повлиять на задержку и пропускную способность. Следует также отметить, что практически нет помех в реализации архитектуры HIP в форме, например, библиотеки прикладного уровня, которая уже фактически была реализована в [xin-hip-lib]. Однако при переносе HIP на уровень приложений могут не поддерживаться унаследованные приложения.

A.2. Недостатки HIP

В информатике многие проблемы можно решить с помощью дополнительного уровня опосредованности. Однако косвенные обращения всегда связаны с определёнными расходами и «бесплатных обедов» не бывает. Издержки для случая HIP перечислены ниже.

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

  • HIP требует управления идентификаторами HI и централизованного подхода к масштабному управлению конечными точками с поддержкой HIP. Прежние ACL на основе адресов IP сейчас стали списками на основе доверенных HIT и сопоставление HIT с IP, а также правила доступа нужно администрировать. Конечные точки с поддержкой HIP должны также быть способны работать автономно для обеспечения мобильности и доступности (конечная точка должна сохранять работоспособность в отсутствие постоянного управляющего соединения). Пользователи, которым нужна повышенная защищенность и мобильность на основе HI вместо ACL по адресам IP, должны затем поддерживать этот дополнительный «уровень отождествления». Как показано в Приложении A.3.5, эти задачи уже решены в настройке инфраструктуры распространения политики и управления отображениями и отношениями доверия между конечными точками HIP.

  • HIP разделяет роли IP адресов как идентификаторов и «локаторов», поэтому требуется механизм сопоставления, чтобы связать их между собой. Неспособность сопоставить HIT с соответствующим «локатором» может приводить к отказам связности, поскольку идентификаторы HIT являются «плоскими» по своей природе и не поддерживают поиска через иерархическую систему DNS. Плоское пространство HIT обусловлено компромиссом в части защиты. Увеличение размера хэша в HIT снижает вероятность (злонамеренных) конфликтов (совпадений).

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

Из-за недостатков развёртывания для контроля доступа к различным службам и устройствам в современной сети Internet обычно применяются МСЭ. Поскольку HIP вносит дополнительное пространство имён, предполагается что для него также будет применяться фильтрация на предмет нежелательных подключений. Хотя это может быть достигнуто с помощью имеющихся средств непосредственно на конечных хостах, фильтры промежуточных устройств потребуется менять с внесением правок в программы имеющихся МСЭ или дополнительных промежуточных устройств [RFC6538].

Обмен ключами вносит дополнительную задержку *2 периода кругового обхода) в организацию транспортного соединения между парой конечных хостов. В TCP дополнительная задержка возникает, если реализация базового сетевого стека отбрасывает пакет SYN в процессе обмена ключами. Такие же издержки могут добавляться процедурами передачи обслуживания в HIP. Однако последующие сеансы TCP с той же ассоциацией HIP не будут добавлять издержек (в течение срока действия ключа). Издержки при обмене ключами и передаче обслуживания можно минимизировать за счёт кэширования пакетов TCP, а передачу обслуживания можно дополнительно оптимизировать с помощью расширений для пользовательского тайм-аута TCP [RFC5482], как подробно описал Schütz с соавторами [schuetz-intermittent].

Наиболее загружающие CPU операции связаны с использованием асимметричных ключей и вывода ключей методом Diffie-Hellman в плоскости управления, но это происходит при обмене ключами, их обслуживании (передача обслуживания и обновление ключевого материала) и завершении ассоциаций HIP. Плоскость данных обычно реализуется с помощью ESP, поскольку это снижает издержки за счёт применения симметричных ключей. Однако и с ESP связаны дополнительные издержки в части задержек (обработка) и пропускной способности (туннелирование), как отмечено в [ylitalo-diss] для оценки производительности.

A.3. Вопросы развёртывания и адаптации

В этом разделе рассмотрены некоторые соображения по развёртыванию и адаптации HIP с технической точки зрения.

A.3.1. Анализ развёртывания

Протокол HIP был адаптирован и развернут в промышленной сети управления производственного предприятия, где строгая идентификация HIP на сетевом уровне поддерживала безопасное сосуществование множества незащищённых сетевых устройств разных производителей [paine-hip]. Протокол HIP был также включён в продукцию защиты для поддержки L2 VPN [henderson-vpls] с целью поддержки зон безопасности в сети диспетчерского контроля и сбора данных (supervisory control and data acquisition или SCADA). Однако HIP не получил «большого успеха» [RFC5218] в Internet, как отмечено Levä и др. [levae-barriers]. Здесь кратко освещены некоторые выводы, основанные на общении с 19 специалистами из сферы промышленности и академических кругов.

С точки зрения маркетинга потребность в HIP была невелика и предпочтение отдавалось другим технологиям. Другая выявленная причина заключалась в сохранении некоторых технических заблуждений, связанных с ранними спецификациями HIP. Два обнаруженных заблуждения состояли в том, что HIP не поддерживает работу через NAT и требует реализации в ядре OS. Оба этих утверждения не соответствуют действительности – HIP включает расширения для работы через NAT [RFC9028], а изменения ядра можно избежать в современных ОС перенаправляя пакеты для обработки в пользовательское пространство.

В анализе Levä и др. приведены инфраструктурные требования для HIP. В минимальном варианте на машинах клиента и сервера должны работать программы HIP. Однако для предотвращения настройки вручную для HIP обычно создаются записи в DNS. Например, популярных DNS-сервер Bind9 не требует каких-либо изменений для размещения записей, связанных с HIP, поскольку он поддерживает двоичный формат в файлах конфигурации [RFC6538]. Серверы HIP rendezvous и МСЭ не являются обязательными. Не требуется вносить изменения в сетевые адреса, NAT, граничные маршрутизаторы и сети ядра.

Анализ также проясняет требования к компонентам хоста, состоящие из трёх частей. Во-первых, требуется плоскость управления HIP, обычно реализуемая в виде демона в пользовательском пространстве. Во-вторых, нужна плоскость данных и большинство реализаций HIP использует режим туннеля со сквозной привязкой (Bound End-to-End Tunnel или BEET) для ESP, доступный в Linux, начиная с ядра 2.6.27, и включенный также в нескольких реализациях в форме программы в пользовательском пространстве. В-третьих, системы HIP обычно обеспечивают DNS-прокси для локального хоста, транслирующий записи HIP DNS в LSI или HIT и передающий соответствующие «локаторы» демону HIP в пользовательском пространстве. Хотя третья часть не является обязательной, она очень полезна для предотвращения настройки вручную. Дополнительное описание этих модулей приведено в отчёте [RFC6538].

На основе обсуждения со специалистами в работе Levä и др. предложены дальнейшие направления для упрощения развёртывания HIP. Перенос ряда спецификаций HIP в IETF Standards Track уже произошёл, но авторы предлагают дополнительные меры, в частности, реализацию HIP в виде библиотеки прикладного уровня [xin-hip-lib] или иной промежуточной программы (middleware). С другой стороны, более осторожные меры включают сосредоточение на частных развёртываниях, контролируемых одной заинтересованной стороной. В качестве более конкретного примера такого сценария HIP может применяться одним сервис-провайдером для организации защищённых соединений между его серверами [komu-cloud].

A.3.2. HIP в сетях 802.15.4

Стандарты IEEE 802 определяют защиту на уровне MAC и многие из них используют расширяемый протокол аутентификации (Extensible Authentication Protocol или EAP) [RFC3748] в качестве системы управления ключами (Key Management System или KMS), но некоторые стандарты, такие как IEEE 802.15.4 [IEEE.802.15.4], оставляют систему KMS и её транспорт вне «области действия». HIP хорошо подходит для таких сред в качестве KMS.

  • HIP не зависит от адресации IP и может транспортироваться напрямую по любому сетевому протоколу.

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

  • Одноранговая KMS может лучше обслуживать специализированные (Ad-hoc) сети 802, чем модель «клиент-сервер» в EAP.

  • Память в некоторых устройствах может быть сильно ограничена, а общая система KMS для защиты MAC и IP даёт существенную экономию кода.

A.3.3. HIP и IoT

HIP требует на устройстве наличия вычислительных ресурсов для криптографической обработки. Протокол может работать в телефонах и небольших устройствах system-on-chip (таких как Raspberry Pi, Intel Edison), но мелкие датчики со слабыми батареями остаются проблематичными. Были разработаны расширения HIP для переноса на мелкие устройства обычно со снижением уровня защиты. Например, были предложены некриптографические идентификаторы для RFID. Подход Slimfit [hummen] предлагает уровень сжатия для HIP, делающий протокол более подходящим для сетей с ограничениями. Этот подход применён в облегчённой версии HIP (Diet HIP) для мелких датчиков.

Обмен HIP Diet EXchange (DEX) [hip-dex] нацелен на снижение издержек, связанных с криптографическими примитивами, за чет отказа от подписей открытых ключей и хэш-функций. При этом сохраняется цель обеспечить свойства защиты, аналогичные базовому обмену (Base Exchange или BEX). Обмен DEX разработан прежде всего для устройств и датчиков с оганиченной памятью и вычислительными ресурсами. Предполагается, что он будет применяться с подходящим протоколом защиты данных вышележащего протокола, таким как ESP. Кроме того, DEX может служить механизмом ввода ключей для примитивов защиты на уровне MAC, например, для сетей IEEE 802.15.9 [IEEE.802.15.9]. Основные отличия между BEX от DEX указаны ниже.

  1. Минимальный набор криптографических примитивов для снижения протокольных издержек:

    • статические пары ключей Elliptic Curve Diffie-Hellman (ECDH) для аутентификации и шифрования сеансового ключа;

    • AES-CTR для симметричного шифрования и AES-CMAC для функции MACing;

    • простая функций свёртки (fold) для генерации HIT.

  2. Отказ совершенной защиты (PFS) с отменой эфемерного согласования ключей Diffie-Hellman.

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

  4. Выводимый с помощью Diffie-Hellman ключ применяется лишь для защиты пакетов HIP. Для создания сеансовых ключей применяется отдельный обмен секретами в пакетах HIP.

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

A.3.4. Инфраструктурные приложения

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

HIP успешно применялся в пересылающих web-прокси (прокси у клиента) между хостом клиента (web-браузер) и пересылающим прокси (сервер Apache), завершающим туннель HIP/ESP. Пересылающий web-прокси транслировал основанный на HIP трафик от клиента в обычный (не HIP) трафик с направлении web-сервера в Internet. Поддерживающий HIP клиент мог взаимодействовать с не понимающими HIP серверами. Таким способом клиент мог использовать поддержку мобильности в HIP при использовании фиксированного IP-адреса на web-прокси, например, для доступа к услугам, которые разрешены лишь для адресов IP из диапазона прокси.

В случае с обратным web-прокси (на стороне сервера), который также был исследован [komu-cloud], не поддерживающий HIP клиент обращался к понимающему HIP сервису web через промежуточный балансировщик нагрузки (HAProxy). Балансировщик транслировал обычный (не HIP) трафик от клиента в трафик на основе HIP для web-сервиса (серверы front-end и back-end). Балансировщик и web-сервис размещались в ЦОД. Одним из ключевых преимуществ шифрования web-трафика с помощью HIP в этом случае была поддержка частного и публичного (гибридного) облака, где балансировщик и серверы front-end и back-end размещаются в разных ЦОД и трафик нужно защищать при передаче через потенциально незащищённые сети между границами частного и публичного облака.

Хотя HIP можно применять для защиты доступа к промежуточным устройствам (например, доступа к коммутаторам по протоколу telnet), он использовался также для защиты соединений в инфраструктуре промежуточных устройств. Например, в более ранним исследовании [komu-mitigation] HIP применялся между почтовыми серверами (Simple Mail Transport Protocol или SMTP) для применения вычислительной головоломки (puzzle) HIP в качестве механизма снижения спама. Достаточно очевидной проблемой в этом случае было отсутствие адаптации HIP на серверах SMTP.

Чтобы избежать проблем развёртывания в имеющейся инфраструктуре, HIP можно использовать в контексте новых протоколов с минимальным развёртыванием. HIP был изучен в контексте некого протокола peer-to-peer SIP [camarillo-p2psip], результатом чего стал набор связанных RFC [RFC6078], [RFC6079], [RFC7086]. Основная идея исследования состояла в предотвращении избыточных трудоёмких процедур ICE путём группировки разных соединений (т. е. SIP и медиапотоки) вместе с использованием низкоуровневого HIP, выполняющего процедуру прохождения NAT лишь один раз на хост. Интересным аспектом было применение инфраструктуры P2P-SIP в качестве серверов встречи для плоскости управления HIP вместо использования традиционных служб HIP rendezvous [RFC8004].

Исследователи предложили применять HIP в сотовых сетях как решение для мобильности, множества адресов и защиты. В [hip-lte] приведён анализ защиты и моделирование применения HIP в транспортных сетях LTE.

HIP изучали в части защиты внутриоблачных соединений сначала с виртуальными машинами [komu-cloud], затем между контейнерами Linux [ranjbar-synaptic]. В обоих случаях HIP предоставлял решение для работы через NAT, которое подходило как внутри облака, так и между разными облаками. В частности, для первого случая HIP обеспечивал постоянную связность с виртуальной машиной при её переносе в другое место, а во втором контроллер программно-определяемой сети (Software-Defined Networking или SDN) служил сервером встреч для поддерживающих HIP контейнеров, обеспечивая надёжную защиту от повторного использования путём добавления middlebox nonce [heer-end-host] для базового обмена HIP и сообщений UPDATE.

A.3.5. Поддержка отождествлений в коммерческих системах

Tempered Networks выпускает продукцию на основе HIP, называя свою платформу сетью на основе отождествлений (Identity-Defined Networking или IDN) [tempered-networks] из за ориентированной на идентификацию архитектуры HIP. Задача заключалась в упрощении и бесперебойном развёртывании служб с поддержкой HIP в рабочих средах для обеспечения прозрачной аутентификации и проверки полномочий устройств, сокрытия, сегментации и сквозного взаимодействия в сети. Цель состоит в устранении большого числа циклических зависимостей, эксплойтов и сложности традиционных сетей на основе адресов, которые препятствуют мобильности и проверяемому контролю доступа к устройствам. Продукция Tempered Networks представляет HIP в нескольких типах устройств.

Коммутаторы и шлюзы HIP

Физические и виртуальные устройства, служащие шлюзами HIP и точками применения правил для приложений без поддержки HIP и расположенных за ними устройств. Для подключения, маскировки и защиты устройств без поддержки HIP не нужно менять IP или инфраструктуру. В настоящее время шлюзы HIP поддерживаются на устройствах x86 и ARM, а также в облаках ESXi, Hyper-V, KVM, AWS, Azure, Google.

Трансляторы и серверы встречи HIP

Физические и виртуальные устройства, служащие маршрутизаторами на основе отождествлений для проверки полномочий и соединения конечных точек HIP без шифрования сессий HIP. Ретранслятор HIP можно развернуть как автономное устройство или в кластере для горизонтальной расширяемости. Все конечные точки с поддержкой HIP, соединяемые и защищаемые ими устройства могут иметь приватные адреса. Платформы предотвращают конфликты IP, поддерживают туннели через NAT (включая NAT операторского класса) и не требуют менять базовую инфраструктуру. Единственным требованием является наличие у конечной точки HIP исходящего доступа в Internet а у ретранслятора HIP – публичного адреса.

Клиенты и серверы с поддержкой HIP

программы, устанавливаемые в сетевой стек хоста и обеспечивающие выполнение правил на хосте. Клиенты HIP поддерживают раздельное туннелирование. Клиенты и серверы HIP могут взаимодействовать с МСЭ на локальном хосте, а сервер можно заблокировать для прослушивания лишь применяемого для HIP порта, что делает его невидимым для неуполномоченных устройств. В настоящее время поддерживаются платформы Windows, OS X, iOS, Android, Ubuntu, CentOS и другие дистрибутивы Linux.

Менеджеры оркестровки правил

Физические и виртуальные устройства для задания и распространения правил сети и защиты (сопоставления HI и IP, наложенные сети, «белые» списки и т. п.) в конечные точки с поддержкой HIP. Оркестровка не требует сохранения в конечных точках HIP и наоборот, что позволяет создавать автономные сети и обеспечивать защиту.

A.4. Ответы на вопросы NSRG

Исследовательская группа IRTF Name Space задала в своём оценочном отчёте ряд вопросов [nsrg-report], ответы на которые представлены ниже.

  1. Как имя стека улучшит общую функциональность Internet?

    HIP отделяет (меж)сетевой уровень от транспортного, позволяя им развиваться независимо. Разделение упрощает мобильность и многоадресность конечных хостов, а также позволяет работать через сети IPv4 и IPv6. HI упрощает смену адресов и миграцию процессов, а также реализацию кластеризованных серверов. Кроме того, криптографическая природа идентификаторов обеспечивает базу для решения вопросов безопасности, связанных с мобильностью и многоадресностью конечных хостов.

  2. Как выглядит имя стека?

    HI является криптографическим открытым ключом, однако вместо непосредственного использования ключа многие протоколы применяют хэш открытого ключа с фиксированным размером.

  3. Каков срок действия идентификатора?

    HIP поддерживает стабильные и временные HI. Стабильные HI обычно имеют длительный срок действия (годы), а для временных срок определяют соединения и приложения вышележащего уровня (от секунд до лет).

  4. Где HI размещаются в стеке?

    Идентификаторы HI находятся между транспортным и (меж)сетевым уровнем.

  5. Как HI используются конечными точками?

    Идентификаторы HI могут применяться приложениями напрямую или опосредовано (в форме HIT или LSI) при обращении к сетевым службам. Кроме того, HI как открытые ключи используются во встроенном протоколе согласования ключей, называемом базовым обменом HIP, для взаимной аутентификации хостов.

  6. Какая административная инфраструктура требуется для поддержки?

    В некоторых средах возможно применение HIP без какой-либо инфраструктуры, однако для полного использования преимуществ HIP идентификаторы HI должны храниться в DNS или PKI, а также нужен «механизм встречи (rendezvous) [RFC8005].

  7. Не делает ли дополнительный уровень ненужным список адресов в SCTP?

    Да, список не нужен.

  8. Какие дополнительные преимущества обеспечивает новая схема именования в части безопасности?

    HIP снижает зависимость от адресов IP, упрощая решение проблемы владения адресами [Nik2001]. На практике HIP обеспечивает защиту для мобильности и многоадресности конечных хостов. Кроме того, идентификаторы HI являются открытыми ключами и поверх HIP может применяться стандартная инфраструктура открытых ключей.

  9. Каким может быть механизм распознавания и какие характеристики требуются от него?

    Для большинства случаев достаточно модели с преобразованием имён DNS сразу в HI и адреса IP. Однако, если требуется преобразование HI в адреса IP или их обратное преобразование в имена DNS, нужна инфраструктура плоского распознавания, которая может быть реализована на основе распределенных хэш-таблиц, но это потребует новых разработок и развёртывания.

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

Люди, участвовавшие в ранних этапах разработки HIP, перечислены в разделе благодарностей спецификации HIP. На финальных этапах подготовки этого документа, когда редактором стал Pekka Nikander, бесценны были комментарии ранних разработчиков и других людей, включая Jari Arkko, Jeff Ahrenholz, Tom Henderson, Petri Jokela, Miika Komu, Mika Kousa, Andrew McGregor, Jan Melen, Tim Shepard, Jukka Ylitalo, Sasu Tarkoma, Jorma Wall. Спасибо также Lars Eggert, Spencer Dawkins, Dave Crocker, Erik Giesa за полезные комментарии.

Авторы выражают особую благодарность Tom Henderson, взявшему на себя задачи редактирования документа в ответ на комментарии IESG, когда оба автора были заняты другими делами. Без его настойчивости документ не достиг бы уровня RFC 4423.

Основная работа по обновлению и продвижению HIP в рамках процесса IETF была проделана несколькими командами разработчиков HIP. Авторы признательны компании Boeing, Helsinki Institute for Information Technology (HIIT), NomadicLab из Ericsson и трём университетам – RWTH Aachen, Aalto, University of Helsinki за их усилия. Без коллективной работы протокол HIP засох бы на лозе IETF как прекрасная концепция.

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

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

Robert Moskowitz (editor)

HTT Consulting

Oak Park, Michigan

United States of America

Email: rgm@labs.htt-consult.com

Miika Komu

Ericsson

Hirsalantie 11

FI-02420 Jorvas

Finland

Email: miika.komu@ericsson.com


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

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

nmalykh@protokols.ru

1В оригинале применяется термин internetworking – межсетевой.

2Internet Engineering Task Force.

3Internet Engineering Steering Group.

4Denial-of-service – отказ в обслуживании.

5Encapsulating Security Payload – инкапсуляция данных защиты.

6Man-in-the-middle – перехват и изменение пакетов в пути с участием человека.

7Overlay Routable Cryptographic Hash Identifier – идентификатор наложенного маршрутизируемого криптографического хэша.

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

RFC 8999 Version-Independent Properties of QUIC

image_print
Internet Engineering Task Force (IETF)                        M. Thomson
Request for Comments: 8999                                       Mozilla
Category: Standards Track                                       May 2021
ISSN: 2070-1721

Version-Independent Properties of QUIC

Независимые от версии свойства QUIC

PDF

Аннотация

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

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

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

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

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

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

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

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

Оглавление

Исключено в варианте HTML

1. Абстрактное описание QUIC

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

2. Фиксированные свойства всех версий QUIC

В дополнение к защищённому мультиплексируемому транспорту QUIC [QUIC-TRANSPORT] протокол позволяет согласовать версию. Это позволяет протоколу меняться с течением времени в соответствии с новыми требованиями. Многие характеристики протокола могут меняться в разных версиях. В этом документе описано подмножество QUIC, которое предназначено оставаться стабильным в новых версиях по мере их разработки и развёртывания. Все эти инварианты не зависят от версии IP. Основной целью этого документа является обеспечение возможности развёртывания новых версий QUIC. Описывая неизменные свойства, этот документ направлен на сохранение возможности ключевых точек QUIC согласовать изменения любого другого аспекта протокола. В результате это гарантирует минимальный объем информации, доступной кому-либо кроме конечных точек. Если это явно не запрещено данным документом, любые аспекты протокола могут меняться в разных версиях.

В Приложении A приведён список некоторых некорректных допущения, которые могут быть сделаны на основе сведений о QUIC версии. Это не относится к другим версиям QUIC.

3. Соглашения и определения

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

Этот документ определяет требования к будущим версиям QUIC, хотя нормативный язык здесь не применяется. В документе используются термины и соглашения о нотации из [QUIC-TRANSPORT].

4. Соглашения о нотации

Формат пакетов описывается с использованием определённой здесь нотации, которая совпадает с применяемой в [QUIC-TRANSPORT].

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

x (A)

Поле x размером A битов.

x (A..B)

Указывает, что x может иметь любой размер от A до B, если A не указано, поле может иметь размер 0, отсутствие B говорит, что размер поля не ограничен. Значения в этом формате всегда завершаются на границе байта.

x (L) = C

Указывает, что x имеет фиксированное значение C, размером L в одной из приведённых выше форм.

x (L) …

Указывает повторение x (возможно пустой набор), где каждый экземпляр имеет размер L.

В документе применяется сетевой порядок байтов (big endian), поля указываются со старшего бита в каждом байте.

Отдельные поля составного поля указываются с именем составного поля. На рисунке 1 представлен пример.

   Example Structure {
     One-bit Field (1),
     7-bit Field with Fixed Value (7) = 61,
     Arbitrary-Length Field (..),
     Variable-Length Field (8..24),
     Repeated Field (8) ...,
   }

Рисунок 1. Пример формата.


5. Пакеты QUIC

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

QUIC определяет два типа заголовка в пакетах – длинный и короткий. Пакеты с длинным заголовком указываются установкой (1) старшего бита в первом байте пакета, в коротких заголовках этот бит сброшен (0).

В пакетах QUIC может применяться защита целостности пакета, включая заголовок. Однако для пакетов QUIC Version Negotiation защита целостности не применяется (см. раздел 6).

Помимо описанных здесь значений содержимое (payload) пакетов QUIC зависит от версии и имеет произвольный размер.

5.1. Длинный заголовок

Формат длинного заголовка показан на рисунке 2.

   Long Header Packet {
     Header Form (1) = 1,
     Version-Specific Bits (7),
     Version (32),
     Destination Connection ID Length (8),
     Destination Connection ID (0..2040),
     Source Connection ID Length (8),
     Source Connection ID (0..2040),
     Version-Specific Data (..),
   }

Рисунок 2. Длинный заголовок QUIC.


В пакете QUIC с длинным заголовком старший бит первого байта имеет значение 1. Остальные биты этого байта зависят от версии. Следующие 4 байта образуют 32-битовое поле Version, описанное в параграфе 5.4. Следующий байт указывает размер следующего за ним поля Destination Connection ID (в байтах). Размер представлен 8-битовым целым числом без знака. Поле Destination Connection ID следует за Destination Connection ID Length и имеет размер от 0 до 255 байтов. Идентификаторы соединений описаны в параграфе 5.3. В следующем байте указан размер поля Source Connection ID, расположенного вслед за ним. Размер представлен 8-битовым целым числом без знака. Поле Source Connection ID следует за Source Connection ID Length и имеет размер от 0 до 255 байтов.

Остальная часть пакета зависит от версии.

5.2. Короткий заголовок

Формат короткого заголовка показан на рисунке 3.

   Short Header Packet {
     Header Form (1) = 0,
     Version-Specific Bits (7),
     Destination Connection ID (..),
     Version-Specific Data (..),
   }

Рисунок 3. Короткий заголовок QUIC.


В пакетах QUIC с коротким заголовком старший бит первого байта имеет значение 0. Пакет QUIC с коротким заголовком включает Destination Connection ID сразу за первым байтом. Короткий заголовок не содержит полей Destination Connection ID Length, Source Connection ID Length, Source Connection ID, Version. Размер Destination Connection ID не указывается в пакетах с коротким заголовком и не ограничивается этой спецификацией.

Остальная часть пакета зависит от версии.

5.3. Идентификатор соединения

Идентификатор соединения представляет собой неанализируемое (opaque) поле произвольного размера. Основным назначением идентификаторов соединения является предотвращение доставки пакетов в соединении QUIC не той конечной точке в случае смены адреса на нижележащих уровнях (UDP, IP и ниже). Идентификаторы соединения используются конечными точками и промежуточными узлами для гарантированной доставки каждого пакета QUIC корректному экземпляру конечной точки. В конечной точке идентификатор соединения служит для указания соединения QUIC, которому предназначен пакет.

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

5.4. Версия

Поле Version содержит 4-байтовый идентификатор, который может применяться конечными точками для указания версии QUIC. Поле Version = 0x00000000 зарезервировано для согласования версии (см. раздел 6), все остальные значения могут быть действительными.

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

6. Согласование версий

Конечная точка QUIC, получившая пакет с длинным заголовком и версией, которую она не понимает или не поддерживает, может передать в ответ пакет Version Negotiation. Пакеты с коротким заголовком не вызывают согласования версии.

В пакете Version Negotiation установлен (1) старший бит первого байта, задающий длинный заголовок, как описано в параграфе 5.1. Пакет Version Negotiation идентифицируется в качестве такового по полю Version = 0x00000000.

   Version Negotiation Packet {
     Header Form (1) = 1,
     Unused (7),
     Version (32) = 0,
     Destination Connection ID Length (8),
     Destination Connection ID (0..2040),
     Source Connection ID Length (8),
     Source Connection ID (0..2040),
     Supported Version (32) ...,
   }

Рисунок 4. Пакет согласования версии.


В первом байте пакета Version Negotiation определено значение лишь старшего бита (1), а остальные 7 битов, помеченные как Unused, могут иметь любые значения при передаче и должны игнорироваться получателем.

После поля Source Connection ID в пакете Version Negotiation содержатся пола Supported Version, каждое из которых указывает версию, поддерживаемую отправившей пакет конечной точкой. Других полей пакет Version Negotiation не содержит. Конечная точка должна игнорировать пакет без поля Supported Version или с усечённым полем. Для пакетов Version Negotiation не обеспечивается защиты целостности и конфиденциальности. Конкретные версии QUIC могут включать элементы протокола, позволяющие конечным точкам обнаруживать изменение или повреждения списка поддерживаемых версий.

Конечная точка должна включать значение Source Connection ID из полученного пакета в поле Destination Connection ID. Значение Source Connection ID должно копироваться из поля Destination Connection ID в полученном пакете, которое исходно клиент задаёт случайным. Указание обоих идентификаторов соединения даёт клиенту некоторую уверенность в том, что сервер получил пакет, а пакет Version Negotiation не создан злоумышленником, способным наблюдать пакеты.

Получившая пакет Version Negotiation конечная точка может сменить версию для последующих пакетов. Условия смены конечной точкой версии QUIC зависят от выбираемой версии.

В документе [QUIC-TRANSPORT] приведено более подробное описание генерации и использования пакетов Version Negotiation конечной точкой, поддерживающей QUIC версии 1.

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

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

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

Описанный в этом документе пакет Version Negotiation не имеет защиты целостности и лишь слегка защищён от злоумышленников. Конечная точка должна проверять подлинность смыслового содержимого Version Negotiation, если она пытается в результате сменить версию QUIC.

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

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

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

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

[QUIC-TLS] Thomson, M., Ed. and S. Turner, Ed., “Using TLS to Secure QUIC”, RFC 9001, DOI 10.17487/RFC9001, May 2021, <https://www.rfc-editor.org/info/rfc9001>.

[QUIC-TRANSPORT] Iyengar, J., Ed. and M. Thomson, Ed., “QUIC: A UDP-Based Multiplexed and Secure Transport”, RFC 9000, DOI 10.17487/RFC9000, May 2021, <https://www.rfc-editor.org/info/rfc9000>.

[RFC5116] McGrew, D., “An Interface and Algorithms for Authenticated Encryption”, RFC 5116, DOI 10.17487/RFC5116, January 2008, <https://www.rfc-editor.org/info/rfc5116>.

Приложение A. Некорректные допущения

Имеются некоторые черты QUIC версии 1 [QUIC-TRANSPORT], не защищённые от наблюдения, но тем не менее, считающиеся изменяемыми в новых версиях. В этом приложении приведены примеры некорректных допущений, которые могут быть приняты на основе сведений о QUIC версии 1. Некоторые из приведённый утверждений неверны даже для QUIC версии 1. Список не является полным и служит лишь иллюстрацией. Любое из приведённых ниже утверждений может быть ошибочным для конкретной версии QUIC.

  • QUIC использует TLS [QUIC-TLS] и некоторые сообщения TLS видимы в линии.

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

  • Каждый поток данного квинтета (5-tuple) включает фазу организации соединения.

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

  • Можно предположить, что последний поток перед долгим бездействием содержит лишь подтверждение.

  • QUIC использует функцию аутентифицированного шифрования со связанными данными (Authenticated Encryption with Associated Data или AEAD) AEAD_AES_128_GCM [RFC5116] для защиты пакетов в процессе организации соединения.

  • Номера пакетов QUIC шифруются и указываются в первых шифрованных байтах.

  • Номера пакетов QUIC увеличиваются на 1 в каждом передаваемом пакете.

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

  • QUIC требует, чтобы соединение инициировал (начинал «говорить») клиент.

  • В пакетах QUIC второй бит первого байта (0x40) всегда установлен (1).

  • Пакеты QUIC Version Negotiation передаёт только сервер.

  • Идентификаторы соединения QUIC меняются нечасто.

  • Конечные точки QUIC меняют применяемую версию, если передан пакет Version Negotiation.

  • Поле Version в пакетах QUIC с длинным заголовком одинаково для обоих направлений.

  • Пакет QUIC с определенным значением поля Version означает использование соответствующей версии QUIC.

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

Адрес автора

Martin Thomson

Mozilla

Email: mt@lowentropy.net


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

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

nmalykh@protokols.ru

1Internet Engineering Task Force.

2Internet Engineering Steering Group.

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

RFC 8993 A Reference Model for Autonomic Networking

image_print
Internet Engineering Task Force (IETF)                 M. Behringer, Ed.
Request for Comments: 8993                                              
Category: Informational                                     B. Carpenter
ISSN: 2070-1721                                        Univ. of Auckland
                                                               T. Eckert
                                                           Futurewei USA
                                                            L. Ciavaglia
                                                                   Nokia
                                                                J. Nobre
                                                                   UFRGS
                                                                May 2021

A Reference Model for Autonomic Networking

Эталонная модель для сетей с самоуправлением

PDF

Аннотация

В этом документе описана эталонная модель для автоматической работы1 (Autonomic Networking или AN) управляемой сети. Определено поведение автоматического узла, совместная работа элементов в контексте самоуправления и использование инфраструктуры автоматическими службами.

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

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

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

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

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

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

Оглавление

Исключено в варианте HTML

1. Введение

В документе «Autonomic Networking: Definitions and Design Goals» [RFC7575] описаны фундаментальные концепции, лежащие в основе автономных сетей (Autonomic Networking), определены термины и высокоуровневая эталонная модель. В [RFC7576] рассматривается «разрыв» между традиционным подходом и автономизацией.

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

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

Например, в имеющейся неавтоматической сети можно регистрировать устройства традиционным способом для создания доверенной инфраструктуры на основе сертификатов. Эту доверенную инфраструктуру затем можно применить для активизации автоматической плоскости управления (Autonomic Control Plane или ACP) и выполнения традиционных сетевых операций через защищённую и самовосстанавливающуюся ACP (см. [RFC8368]).

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

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

2. Представление сети

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

На рисунке 1 показано высокоуровневое представление сети с самоуправлением (AN). Сесть состоит из множества автоматических узлов, которые взаимодействуют между собой напрямую. Эти автоматические узлы обеспечивают в сети общий набор возможностей (свойств), который называется инфраструктурой автоматической сети (Autonomic Networking Infrastructure или ANI). Инфраструктура ANI обеспечивает такие функции, как именование, адресация, синхронизация, обнаружение и обмен сообщениями.

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

+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
:            :     Автоматическая функция 1      :                 :
: ASA 1      :      ASA 1      :      ASA 1      :          ASA 1  :
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
             :                 :                 :
             :   +- - - - - - - - - - - - - - +  :
             :   :  Автоматическая функция 2  :  :
             :   :  ASA 2      :      ASA 2   :  :
             :   +- - - - - - - - - - - - - - +  :
             :                 :                 :
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
:                Инфраструктура автоматической сети                :
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
+--------+   :    +--------+   :    +--------+   :        +--------+
| Узел 1 |--------| Узел 2 |--------| Узел 3 |----...-----| Узел n |
+--------+   :    +--------+   :    +--------+   :        +--------+

Рисунок 1. Высокоуровневое представление сети с самоуправлением.


По горизонтали автоматические функции охватывают всю сеть, а также ANI. По вертикали сеть всегда реализует ANI и может включать один или несколько агентов ASA, которые могут быть автономными или включать в себя другие ASA (иерархия). Таким образом, ANI служит основой для автоматических функций.

3. Самоуправляемый элемент сети

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

3.1. Архитектура

В этом параграфе описывается элемент AN и его внутренняя архитектура. Эталонная модель из «Autonomic Networking: Definitions and Design Goals» [RFC7575] показывает источники информации, которые может использовать ASA – самообучение, изучение сети (с помощью обнаружения), Intent (см. параграф 7.2) и контуры обратной связи. Внутри автоматического узла имеется два уровня – уровень ASA и уровень ANI, причём первый использует услуги второго. Эта концепция показана на рисунке 2.

+------------------------------------------------------------+
|                                                            |
| +-----------+        +------------+        +------------+  |
| |   Агент   |        |   Агент    |        |   Агент    |  |
| | автоматич.|        | автоматич. |        | автоматич. |  |
| | службы 1  |        | службы 2   |        | службы 3   |  |
| +-----------+        +------------+        +------------+  |
|       ^                    ^                     ^         |
| -  -  | -  - Уровень API  -| -  -  -  -  -  -  - |-  -  -  |
|       V                    V                     V         |
|------------------------------------------------------------|
| Инфраструктура автоматической сети                         |
|    - структуры данных (сертификаты, сведения о партнёрах)  |
|    - обобщённая автоматическая плоскость управления (GACP) |
|    - адресация и именование автоматического узла           |
|    - функции обнаружения, согласования и синхронизации     |
|    - распространение намерений (Intent) и другой информации|
|    - агрегированные отчёты и контуры обратной связи        |
|    - маршрутизация                                         |
|------------------------------------------------------------|
|           Функции базовой операционной системы             |
+------------------------------------------------------------+

Рисунок 2. Модель автоматического узла.


Инфраструктура ANI (нижняя часть рисунка 2) содержит зависящие от узла структуры данных (например, сведения о доверии для самого узла и его партнёров), а также базовый набор функций, не зависящий от конкретного применения. Этой инфраструктуре следует быть общей и поддерживать разные ASA (верхняя часть рисунка 2). ANI включает адресацию и именование автоматических узлов, распространение информации, передачу отчётов, контуры обратной связи и маршрутизацию внутри плоскости управления ACP.

Обобщённая плоскость управления (Generalized ACP или GACP) – это сводка всех взаимодействий ANI с другими узлами и службами. Конкретная реализация GACP в этом документе обозначается ACP и описана в [RFC8994].

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

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

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

3.2. Таблица смежности

Самоуправляемые сети AN основаны на прямом взаимодействии между узлами домена. Плоскость управления ACP обычно строится на пошаговой основе (hop-by-hop), поэтому многие взаимодействия в ANI основываются на таблице смежности. Некоторые взаимодействия вносят сведения в эту таблицу, а другие используют данные из таблицы.

Таблица смежности ANI содержит по меньшей мере сведения о смежных автоматических узлах: Node-ID, IP-адрес в плоскости данных, IP-адрес в ACP, домен и сертификат. Автоматический узел поддерживает актуальность сведений в таблице. Таблица содержит сведения лишь об узлах, поддерживающих AN, а узлы без самоуправления обычно не отслеживаются в таблице. Однако информация отслеживается независимо от статуса партнёров, в частности, таблица смежности содержит сведения о незарегистрированных узлах того же или иного домена. Таблица смежности может включать сведения о действительности смежных автоматических узлов и уровне доверия к ним.

В таблицу смежности поступают указанные ниже данные.

  • Обнаружение локальных соединений (Link-local). Это взаимодействие происходит в плоскости данных с использованием лишь адресации IPv6 link-local, поскольку этот тип адресации сам является автоматическим. Этот способ позволяет узлу изучить автоматические узлы вокруг себя. Процедуру обнаружения локальных соединений описывают документы [RFC8990], [RFC8995], [RFC8994].

  • Перенаправление от производителя. Новое устройство может получать информацию о местоположении его домашней сети через перенаправление от уполномоченного производителем удостоверяющего центра (Manufacturer Authorized Signing Authority или MASA), как указано в параграфе 5.3. Обычно это маршрутизируемый адрес.

  • Неавтоматический ввод. Узел можно настроить вручную с участием автоматического партнёра, о котором узел может узнать из опций DHCP, DNS или иных неавтоматических механизмов. Обычно такие механизмы требуют того или иного участия администратора. Основной целью является обход (bypass) неавтоматического устройства или сети. Для новых устройств этот вопрос рассматривается в Приложениях A и B к [RFC8995].

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

  • Если узел не загрузился (bootstrap) в домен (т. е. не имеет сертификата домена), он проходит один за другим все узлы в таблице смежности, заявляющие присутствие в домене, и пытается загрузиться через них. Одним из возможных откликов является перенаправления через MASA производителя, которое будет введено в таблицу смежности (см. выше и [RFC8995]).

  • Если смежный узел относится к тому же домену, он аутентифицирует данный узел и при успешной проверке подлинности организует ACP (см. [RFC8994]).

  • Как только узел становится частью ACP в домене, он будет использовать GRASP [RFC8990] для поиска регистраторов домена и, возможно, других служб.

  • Если узел является частью ACP и нашёл хотя бы один регистратор в домене с помощью GRASP, он запускает ASA и будет выступать как прокси присоединения для соседей, которым нужна загрузка (см. параграф 6.3.1.2).

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

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

Автоматические функции состоят из ASA. Они работают логически на базе инфраструктуры ANI и могут использовать таблицу смежности, ACP, согласование и синхронизацию через GRASP в ACP, Intent и другие функции ANI. Поскольку ANI обеспечивает лишь автоматическое взаимодействие внутри домена, автоматические функции могут также использовать любой другой контекст на узле, в частности, глобальную плоскость данных.

3.3. Конечный автомат

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

Обычно предполагается, что устройство сохраняет связанное с доменом отождествление – Local Device Identifier (LdevID, см. параграф 5.2) – в постоянном хранилище, которое будет доступно после выключения и последующего включения питания. Для устройств, не способных постоянно сохранять LDevID выключения питания равносильно сбросу к заводским настройкам.

3.3.1. Состояние 1 – заводские установки

Автоматический узел выпускается с завода в этом состоянии. Узел не имеет связанных с доменом настроек, в частности LDevID, и может использоваться в любой конкретной сети. Однако узел имеет заданный производителем идентификатор (Initial Device Identifier или IDevID) [IDevID]. Узлы без IDevID невозможно автоматически и безопасно зарегистрировать в домене, они требуют предварительной настройки вручную и в этом случае подготовка начинается из состояния 2.

Переходы

  • Загрузка. Устройство регистрируется в домене, получая при этом доменное отождествление – LDevID. При успешной регистрации следующим будет состояние 2. регистрация описана в [RFC8995].

  • Включение и выключение питания. Устройство теряет все таблицы состояний и остаётся в состоянии 1.

3.3.2. Состояние 2 – устройство зарегистрировано

Автоматический узел находится в зарегистрированном (enrolled) состоянии, если у него имеется LdevID и в настоящее время нет канала ACP. Узел может иметь дополнительную конфигурацию или состояние, если он находился, например, в состоянии 3, но потерял все свои каналы ACP. Идентификатор LDevID можно удалить с устройства только при сбросе к заводским настройкам и при этом будут удалены все прочие состояния устройства. Это гарантирует отсутствие устаревшего доменного состояния при регистрации из состояния 1.

Переходы

  • Присоединение к ACP. Устройство организует канал ACP к смежному устройству (см. [RFC8994]). Следующим будет состояние 3.

  • Сброс к заводским настройкам. Удаляются все конфигурации и доменное отождествление LdevID. Следующим будет состояние 1.

  • Включение и выключение питания. Устройство теряет все таблицы состояния, но сохраняет доменное отождествление LdevID и остаётся в состоянии 2.

3.3.3. Состояние 3 – устройство подключено к ACP

В этом состоянии автоматический узел имеет хотя бы 1 канал ACP к другому устройству. Узел теперь может участвовать в других автоматических транзакциях, таких как запуск ASA (например, он должен включить прокси-ASA для присоединения, чтобы помочь другим устройствам войти в домен). К таким взаимодействиям могут применяться другие условия, например, для работы в качестве посредника в присоединении, устройство сначала должно найти регистратор загрузки.

Переходы

  • Выход из ACP. Устройство отключает последний (единственный) канал ACP к смежному устройству. Следующим будет состояние 2.

  • Сброс к заводским настройкам. Удаляются все конфигурации и доменное отождествление LdevID. Следующим будет состояние 1.

  • Включение и выключение питания. Устройство теряет все таблицы состояния, но сохраняет доменное отождествление LdevID. Следующим будет состояние 2.

4. Инфраструктура AN

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

4.1. Именование

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

При отсутствии специфической для домена схемы именования следует применять принятую по умолчанию схему, использующую такую же логику как схема адресации, описанная в [RFC8994]. Имя устройства в этом случае состоит из Registrar-ID (например, MAC-адрес регистратора) и номера устройства. Примером такого имени может служить

   0123-4567-89ab-0001

Первые 3 поля этого имени образованы MAC-адресов, а четвёртое содержит порядковый номер устройства.

4.2. Адресация

Агенты ASA должны взаимодействовать друг с другом, используя автоматическую адресацию инфраструктуры ANI узла, на котором размещается агент. В этом параграфе описан подход к адресации ANI используемой агентами ASA. Подход к адресации в плоскости данных сети выходит за рамки этого документа. Эта адресация может настраиваться и управляться традиционным способом или согласовываться как услуга ASA. Один из примеров использования такой автономной функции представлен в [RFC8992].

Автоматическая адресация является функцией ANI (нижняя часть рисунка 2) и, в частности ACP. Агенты ASA не имеют собственных адресов. Они могут использовать вызовы API или схему автоматической адресации ANI. Требования к схеме автоматической адресации перечислены ниже.

  • Адресация без вмешательства (Zero-touch) для простых сетей, которым следует иметь полное самоуправление адресацией и не требовать централизованного управления, инструментов и планирования.

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

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

  • Устойчивость. Возможность негативного влияния администратора на адресацию (и связность) следует предотвращать в контексте сети с самоуправлением.

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

  • Поддержка виртуализации. Автоматические функции могут работать на уровне физической сети и устройств или на уровне виртуальных машин, контейнеров и сетей. В частности, автоматические узлы могут поддерживать ASA в виртуальных объектах. Инфраструктуре и схеме адресации, следует поддерживать это.

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

  • Расширяемость. Схема адресации должна работать в сетях любого размера.

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

Предлагаемая схема адресации описана в документе «An Autonomic Control Plane (ACP)» [RFC8994].

4.3. Обнаружение

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

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

Во-вторых, для сетевых служб, таких как аутентификация, проверка полномочий и учёт (Authentication, Authorization, Accounting или AAA), также следует поддерживать обнаружение без настройки. Сеть с самоуправлением (AN) может использовать имеющиеся функции обнаружения, применять новые подходы или то и другое вместе.

Таким образом, механизмы обнаружения могут быть полностью объединены с автоматической сигнализацией (см. следующий параграф) или использовать независимые механизмы, такие как обнаружение служб через DNS или Service Location Protocol. Выбор может быть независимым для каждого агента ASA, хотя инфраструктура может требовать того или иного общего минимума (например, обнаружение механизма защищённой загрузки или источника распространения информации, см. параграф 4.7).

В фазе 1 сети с самоуправлением (Autonomic Networking) используют для обнаружения протокол GRASP [RFC8990].

4.4. Сигнализация между автоматическими узлами

Автоматические узлы должны взаимодействовать между собой, например, для согласования и/или синхронизации технических целей (т. е. параметров сети) любого типа и сложности. Для этого нужна та или иная форма сигнализации между узлами. Автоматические узлы, реализующие определённый вариант, могут выбрать свой сигнальный протокол, если он соответствует общей модели безопасности. Однако в общем случае обмен данными может потребоваться любой паре узлов с самоуправлением, поэтому нужен общий протокол сигнализации. Предпосылкой для этого является возможность узлов обнаруживать друг друга без предварительной настройки, как отмечено выше. Для обеспечения общего характера обнаружение и сигнализация должны быть способны решать любые технические задачи, включая те, которым нужны сложные структуры данных. В документе «GeneRic Autonomic Signaling Protocol (GRASP)» [RFC8990] более подробно описаны требования к обнаружению, согласованию и синхронизации в AN. Документ также определяет протокол GRASP для этих целей, включающий встроенный, но необязательный процесс обнаружения.

Обычно предполагается, что GRASP работает внутри ACP (см. параграф 4.6) и зависит от ACP в плане безопасности. Возможна кратковременная работа протокола без защиты в процессе начальной загрузки (bootstrap). На автоматическом узле обычно работает один экземпляр GRASP, используемый несколькими агентами ASA. Однако не исключается использование на узле нескольких экземпляров GRASP, возможно с разными свойствами защиты.

4.5. Маршрутизация

Все автоматические узлы в домене должны быть способны взаимодействовать друг с другом, а на последующих фазах – ещё и с автоматическими узлами других доменов. Поэтому ACP полагается на функцию маршрутизации. Для взаимодействия сетей с самоуправлением они должны поддерживать общий протокол маршрутизации. В документе ACP [RFC8994] определён протокол маршрутизации для AN.

4.6. Автоматическая плоскость управления

Плоскость управления ACP поддерживает протоколы управления в автоматической сети AN. В описанной здесь архитектуре она реализована как наложенная сеть. В документе «An Autonomic Control Plane (ACP)» [RFC8994] описаны детали реализации. Данный документ использует термин «наложенная» (overlay) для обозначения набора парных смежностей с базовой топологией соединений. Это может отличаться от толкования термина overlay в контексте маршрутизации. Примеры использования ACP приведены в [RFC8368].

4.7. Распространение информации (*)

Некоторые формы информации требуют распространения через домен с самоуправлением. Такое распространение происходит в плоскости управления ACP. Например Intent распространяется по домену, как описано в [RFC7575]. Намерения (Intent) являются языком правил в сети с самоуправлением AN (см. параграф 7.2). Это правила высокого уровня и менять их следует нечасто (дни). Поэтому такую информацию, как Intent, следует рассылать в лавинном режиме всем узлам автоматического домена и в настоящее время нет ощутимой потребности использовать более направленные методы распространения. Предполагается, что Intent будет «монолитным» и рассылаться будет целиком. Один из возможных методов распространения Intent и других форм данных рассмотрен в [GRASP-DISTRIB]. Intent и распространение информации не входят в задачи рабочей группы ANIMA.

5. Инфраструктура защиты и доверия

Автоматические сети AN сами защищают себя. Все протоколы по умолчанию являются защищёнными и не требуют привлечения администратора для явной настройки защиты за исключением установки инфраструктуры PKI.

Автоматические узлы взаимодействуют напрямую и это требует защиты. Поскольку сети AN не полагаются на настройку конфигурации, здесь нет опций настройки, таких как заранее распространённые ключи и вместо этого должна применяться доверенная инфраструктура, такая как PKI. В этом разделе описаны принципы инфраструктуры доверия. На первой фазе AN устройство 1) находится в доверенном домене и само является доверенным или 2) находится за пределами домена доверия и считается недоверенным.

Принятый по умолчанию метод автоматического запуска инфраструктуры доверия определён в документе «Bootstrapping Remote Secure Key Infrastructure (BRSKI)» [RFC8995]. Агенты ASA, требуемые для регистрации, описаны в параграфе 6.3. Автоматические узлы должны реализовать агенты ASA для регистрации и посредничества в присоединении. ASA-регистратор можно реализовать на части устройств.

5.1. Инфраструктура открытых ключей

Домен с самоуправлением использует модель PKI. Конем доверия является удостоверяющий центр (Certification Authority или CA). Регистратор выступает в качестве центра регистрации (Registration Authority или RA). Минимальная реализация автоматического домена содержит один CA, один регистратор и элементы сети.

5.2. Сертификат домена

Каждое устройство в домене самоуправления использует сертификат домена (LdevID) для отождествления себя. Новое устройство использует предоставленный производителем сертификат IdevID в процессе начальной загрузки для получения сертификата LdevID. Процесс получения доменного сертификата и его формат описаны в [RFC8995].

5.3. MASA

Уполномоченный производителем орган подписания (Manufacturer Authorized Signing Authority или MASA) является доверенной службой для устройств с начальной загрузкой. MASA позволяет владельцу отслеживать устройства в домене, обеспечивая регистратору аудит, проверку полномочий и маркеры владения в процессе начальной загрузки, чтобы помочь при проверке подлинности устройств, пытающихся присоединиться к домену самоуправления и позволить присоединяющемуся устройству проверить корректность домена. Детали службы MASA, безопасности и применения описаны в [RFC8995].

5.4. Субдомены (*)

По умолчанию субдомены считаются отдельными доменами. Это предполагает отсутствие доверия между доменом и его субдоменами, а также между субдоменами одного домена. В частности не создаётся ACP, а Intent действует лишь в домене, для которого намерения заданы явно.

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

5.5. Кросс-доменная функциональность (*)

По умолчанию разные домены не могут взаимодействовать, ACP не создаётся и доверия между доменами нет. В будущем могут быть созданы модели с полным или частичным доверием между доменами.

6. Автоматические агенты служб

В этом разделе описана работа автоматических служб в инфраструктуре ANI.

6.1. Общее описание ASA

Агент ASA определён в [RFC7575] как: «Агент, реализованный на автоматическом узле и выполняющий автоматическую функцию частично (распределенная функция) или полностью. Таким образом, это процесс, использующий функции инфраструктуры ANI для достижения своих целей, обычно путём взаимодействия с другими ASA по протоколу GRASP [RFC8990] или иным способом. Агент также взаимодействует с конкретными объектами (target) своей функции, используя любой подходящий механизм. Если функция агента не очень проста, ASA потребуется обрабатывать перекрывающиеся асинхронные операции. Поэтому агент может быть достаточно сложной частью программы, работающей на прикладном уровне над инфраструктурой ANI. Рекомендации по проектированию ASA приведены в [ASA-GUIDELINES].

Можно выделить по меньшей мере 3 класса агентов ASA:

  • простые ASA небольшого размера, которые могут работать где угодно;

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

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

Автоматические узлы и их агенты ASA знают свои возможности и ограничения, связанные с оборудованием, микрокодом (firmware) и установленными программами, т. е. «осознают себя» (self-aware).

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

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

Поскольку агенты ASA будут взаимодействовать с ANI, они будут зависеть от соответствующих интерфейсов API2. Желательна переносимость ASA между разными операционными системами, поэтому от API требуется универсальность. Интерфейс API для протокола GRASP описан в [RFC8991]. В общем случае агенты ASA будут разрабатываться и кодироваться специалистами в конкретной технологии и варианте применения, а не специалистами в части инфраструктуры ANI и её компонентов. Кроме того, они могут представляться на разных языках программирования, в частности, на языках, поддерживающих объекты, а также традиционные переменные и структуры. При разработке API это следует учитывать.

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

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

Агенты ASA автоматически используют возможности защиты, обеспечиваемой инфраструктурой ANI, в частности ACP и GRASP. Однако в дополнение к этому агенты сами отвечают за свою защиту, особенно при взаимодействии с конкретными объектами (target) своей функции. Поэтому при разработке ASA должен выполняться анализ безопасности сверх использования защиты ANI.

6.2. Управление жизненным циклом ASA

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

  • установки ASA, состоящей из копирования кода ASA на узел и его запуска;

  • развёртывания ASA, связывающего экземпляр ASA с управляемым сетевым устройством (устройствами) или функцией;

  • контроль исполнения ASA, задающий цикл управления ASA.

Жизненный цикл также определяет взаимодействия ASA с ANI в разных состояниях. Важные взаимодействия указаны ниже.

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

  • Контроль контура управления ASA в процессе исполнения. Сигнализация передаёт форматированные сообщения для управления исполнением ASA (по меньшей мере запуском и остановкой контура управления).

6.3. Конкретные ASA в инфраструктуре автоматической сети

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

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

6.3.1. Регистрационные ASA

6.3.1.1. ASA-поручитель

Этот агент ASA включает функцию автоматического узла, который выполняет начальную загрузку в домен с помощью посредника в присоединении (join proxy ASA). Такой узел называют поручителем (pledge) в процессе регистрации. Он должен по умолчанию устанавливаться на всех узлах, которым нужна начальная загрузка без предварительной настройки (zero-touch bootstrap).

6.3.1.2. ASA-посредник присоединения

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

6.3.1.3. ASA-регистратор присоединения

Этот агент ASA включает функцию регистратора присоединения (Join Registrar) к автоматической сети AN. Такой агент не требуется устанавливать на всех узлах, достаточно разместить его на узлах с функцией Join Registrar.

6.3.2. ACP ASA

Этот агент ASA включает функцию плоскости управления ACP в автоматической сети AN. В частности, он обнаруживает другие потенциальные узлы ACP и поддерживает организацию и разрыв каналов ACP. Этот агент ASA должен устанавливаться на всех узлах. Подробное описание приведено в параграфе 4.6 и [RFC8994].

6.3.3. ASA для распространения информации (*)

Этот агент ASA выходит за рамки работы группы ANIMA и здесь представлен лишь в качестве справки.

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

Отметим, что распространение информации может быть реализовано как функция в любом агенте ASA. Более подробное описание распространения информации дано в [GRASP-DISTRIB].

7. Управление и программируемость

В этом разделе рассматривается управление и программирование AN.

7.1. Управление (частично) автоматической сетью

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

  • Автоматические функции могут применять традиционные методы и протоколы (например, SNMP и NETCONF) для выполнения задач управления внутри или вне ACP.

  • Автоматические функции могут вызывать конфликты с некоторыми традиционными методами и протоколами.

  • Традиционные функции могут использовать ACP, например, когда ещё нет доступности в плоскости данных.

Автоматические намерения (Intent) определяются на высоком уровне абстракции. Однако в силу необходимости обращения к отдельным управляемым элементам, автоматическому управлению нужны коммуникации на более низких уровнях (например, команды и запросы). Предполагается, что настройка конфигурации таких элементов будет выполняться, например, с использованием NETCONF и модулей YANG, а мониторинг – с помощью SNMP и MIB.

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

7.2. Намерения (*)

В текущих спецификациях реализаций Intent не рассматривается и в этом параграфе обсуждаются темы дальнейших исследований. Параграф содержит обзор Intent и способы управления намерениями. Intent и сетевое управление на основе правил (Policy-Based Network Management или PBNM) уже описаны в IETF (например, Policy Core Information Model или PCIM) и других органах стандартизации (Standards Development Organization или SDO), например, целевой группе по распределенному управлению (Distributed Management Task Force или DMTF).

Намерения (Intent) можно описать в абстрактной, декларативной политике высокого уровня, используемой для работы автоматического домена, такого как сеть предприятия [RFC7575]. Намерения следует ограничивать лишь высокоуровневыми рекомендациями, т. е. они не должны напрямую определять правила для каждого элемента сети в отдельности.

Intent можно уточнять до политики более низкого уровня с использованием различных подходов. Предполагается, что позволит приспособить намерения к возможностям управляемых устройств. Intent может содержать сведения о ролях и функциях, которые можно транслировать на конкретные узлы [RFC7575]. Одним из возможных уточнений Intent является применение правил «событие-условия-действие» (Event-Condition-Action или ECA).

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

Более подробное рассмотрение Intent приведено в [ANIMA-INTENT]. Для распространения Intent и других типов информации применяется протокол GRASP, см. [GRASP-DISTRIB].

7.3. Агрегированные отчёты (*)

Агрегированные отчёты не включены в текущие спецификации реализаций и в этом параграфе рассматриваются темы дальнейших исследований.

Автоматическим сетям AN следует минимизировать вовлечение операторов. С точки зрения поведения сети это выполняется с помощью автоматических намерений Intent, предоставляемых оператором. Аналогичным образом отчётам с описанием рабочего состояния сети следует агрегировать информацию от разных элементов сети для представления эффективности исполнения Intent. Поэтому отчёты в AN следует предоставлять на уровне сети [RFC7575].

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

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

7.4. Контуры обратной связи с NOC (*)

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

Однонаправленные уведомления в центр управления сетью (Network Operations Center или NOC), которые не предлагают заданных по умолчанию действий и не допускают переопределения в рамках транзакции, рассматриваются подобно традиционным службам уведомления, таким как syslog. Предполагается их сосуществование с автономными методами, но этот вопрос в документе не рассматривается.

7.5. Контуры управления (*)

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

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

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

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

7.6. API (*)

В [RFC8991] определена концептуальная схема API для протокола базовой автоматической сигнализации (GeneRic Autonomic Signaling Protocol или GRASP). Этот API разработан для взаимодействия между агентами ASA по протоколу GRASP. Полная спецификации Standards Track API не включены в текущий спецификации реализаций.

Большинство API являются статическими, что означает их предопределённость и использование инвариантных механизмов работы с данными. Автоматическим сетям AN следует иметь возможность использования динамических API в дополнение к статическим.

Динамические API извлекают данные с использованием базового механизма и затем позволяют клиенту просматривать полученные данные и работать с ними. Такие API обычно используют самоанализ и/или рефлексию. Самоанализ помогает программам проверять типы и свойства объектов в процессе работы, а рефлексия позволяет программе манипулировать атрибутами, методами и/или метаданными объекта.

API должны быть способны выражать и сохранять семантику моделей данных. Например, программные соглашения [Meyer97] основаны на том, что интенсивно использующая программы система (такая как AN) является набором компонентов, чьи взаимодействия основаны на точно определённых спецификациях взаимных обязательств, которые нужно соблюдать. Обычно это включает указание:

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

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

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

7.7. Модели данных (*)

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

Определения модели данных и информационной модели адаптированы из [SUPA-DATA].

Информационная модель – это представление концепций, представляющих интерес для среды, в форме, независимой от репозитория, языка определения данных, языка запросов, языка реализации и протокола. Модель данных – это представление тех же концепций в форме, зависящей от хранилища, языка определения данных, языка запросов, языка реализации и протокола.

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

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

Модель данных важна для некоторых типов функций, таких как цикл адаптивного управления MRACL (Model-Reference Adaptive Control Loop. В более общем смысле модель данных может служить для определения объектов, атрибутов, методов и взаимоотношений программной системы (например, ANI, автоматического узла или агента ASA). Модель данных можно использовать при разработке API, а также любого языка для взаимодействия с сетью AN.

8. Координация между автоматическими функциями (*)

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

8.1. Проблема координации (*)

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

Между автоматическими функциями может быть несколько типов взаимодействия, например:

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

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

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

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

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

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

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

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

8.2. Функциональный блок координации (*)

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

Для общего функционального блока координации требуется:

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

  • общее представление информации и знаний (например, план взаимодействий);

  • общий интерфейс команд (управления) между «агентом» координации и автоматическими функциями.

Могут также предоставляться руководства, рекомендации или BCP для аспектов, относящихся к стратегии и механизмам координации.

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

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

Если система имеет уязвимости в реализации или при работе (настройки), внешний атакующий может использовать такие уязвимости, чтобы стать внутренним (проникнуть в сеть).

9.1. Защита от внешних атак

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

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

  • защищённые от изменения;

  • аутентифицированные;

  • защищённые от replay-атак;

  • защищённые в части конфиденциальности (шифрованные).

Кроме того, протоколам AN следует быть стойкими к отбрасыванию пакетов и перехвату с участием человека (man-in-the-middle или MITM). Эти требования задаются в документах AN Standards Track, определяющих применяемые методы, в частности в [RFC8990], [RFC8994], [RFC8995].

Большинство сообщений AN передаётся в криптографически защищённой плоскости управления ACP. Незащищёнными сообщениями AN вне ACP являются лишь сообщения простого метода обнаружения, описанные в параграфе 2.5.2 [RFC8990], – сообщения DULL (Discovery Unsolicited Link-Local), для которых заданы детальные правила.

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

9.2. Риск внутренних атак

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

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

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

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

  • Использование ещё неизвестных уязвимостей в AN или ином протоколе. Эта угроза относится к любой сети.

Указанные выше угрозы в принципе сравнимы с угрозами для других решений – при наличии ошибок в проектировании, реализации или эксплуатации невозможно гарантировать безопасность. Однако распределенная природа AN и особенно ACP значительно расширяет фронт атак. Например, взломанное устройство может иметь полную доступность по протоколу IP ко всем другим устройствам в ACP, а также применять все методы и протоколы AN.

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

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

Этот документ не запрашивает действий IANA.

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

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

[IDevID] IEEE, “IEEE Standard for Local and metropolitan area networks – Secure Device Identity”, IEEE 802.1AR, <https://1.ieee802.org/security/802-1ar>.

[RFC8990] Bormann, C., Carpenter, B., Ed., and B. Liu, Ed., “GeneRic Autonomic Signaling Protocol (GRASP)”, RFC 8990, DOI 10.17487/RFC8990, May 2021, <https://www.rfc-editor.org/info/rfc8990>.

[RFC8994] Eckert, T., Ed., Behringer, M., Ed., and S. Bjarnason, “An Autonomic Control Plane (ACP)”, RFC 8994, DOI 10.17487/RFC8994, May 2021, <https://www.rfc-editor.org/info/rfc8994>.

[RFC8995] Pritikin, M., Richardson, M., Eckert, T., Behringer, M., and K. Watsen, “Bootstrapping Remote Secure Key Infrastructure (BRSKI)”, RFC 8995, DOI 10.17487/RFC8995, May 2021, <https://www.rfc-editor.org/info/rfc8995>.

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

[ANIMA-INTENT] Du, Z., Jiang, S., Nobre, J. C., Ciavaglia, L., and M. Behringer, “ANIMA Intent Policy and Format”, Work in Progress, Internet-Draft, draft-du-anima-an-intent-05, 14 February 2017, <https://tools.ietf.org/html/draft-du-anima-an-intent-05>.

[ASA-GUIDELINES] Carpenter, B., Ciavaglia, L., Jiang, S., and P. Peloso, “Guidelines for Autonomic Service Agents”, Work in Progress, Internet-Draft, draft-ietf-anima-asa-guidelines-00, 14 November 2020, <https://tools.ietf.org/html/draft-ietf-anima-asa-guidelines-00>.

[GRASP-DISTRIB] Liu, B., Ed., Xiao, X., Ed., Hecker, A., Jiang, S., Despotovic, Z., and B. Carpenter, “Information Distribution over GRASP”, Work in Progress, Internet-Draft, draft-ietf-anima-grasp-distribution-02, 8 March 2021, <https://tools.ietf.org/html/draft-ietf-anima-grasp-distribution-02>.

[Meyer97] Meyer, B., “Object-Oriented Software Construction (2nd edition)”, Prentice Hall, ISBN 978-0136291558, 1997.

[RFC7575] Behringer, M., Pritikin, M., Bjarnason, S., Clemm, A., Carpenter, B., Jiang, S., and L. Ciavaglia, “Autonomic Networking: Definitions and Design Goals”, RFC 7575, DOI 10.17487/RFC7575, June 2015, <https://www.rfc-editor.org/info/rfc7575>.

[RFC7576] Jiang, S., Carpenter, B., and M. Behringer, “General Gap Analysis for Autonomic Networking”, RFC 7576, DOI 10.17487/RFC7576, June 2015, <https://www.rfc-editor.org/info/rfc7576>.

[RFC8368] Eckert, T., Ed. and M. Behringer, “Using an Autonomic Control Plane for Stable Connectivity of Network Operations, Administration, and Maintenance (OAM)”, RFC 8368, DOI 10.17487/RFC8368, May 2018, <https://www.rfc-editor.org/info/rfc8368>.

[RFC8991] Carpenter, B., Liu, B., Ed., Wang, W., and X. Gong, “GeneRic Autonomic Signaling Protocol Application Program Interface (GRASP API)”, RFC 8991, DOI 10.17487/RFC8991, May 2021, <https://www.rfc-editor.org/info/rfc8991>.

[RFC8992] Jiang, S., Ed., Du, Z., Carpenter, B., and Q. Sun, “Autonomic IPv6 Edge Prefix Management in Large-Scale Networks”, RFC 8992, DOI 10.17487/RFC8992, May 2021, <https://www.rfc-editor.org/info/rfc8992>.

[SUPA-DATA] Halpern, J. and J. Strassner, “Generic Policy Data Model for Simplified Use of Policy Abstractions (SUPA)”, Work in Progress, Internet-Draft, draft-ietf-supa-generic-policy-data-model-04, 18 June 2017, <https://tools.ietf.org/html/draft-ietf-supa-generic-policy-data-model-04>.

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

Вклад в работу и отклики предоставили Sheng Jiang, Roberta Maglione, Jonathan Hansford, Jason Coleman, Artur Hecker. Полезные рецензии представили Joel Halpern, Radia Perlman, Tianran Zhou, Christian Hopps.

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

Значительный вклад в документ внесли John Strassner (Huawei), Bing Liu (Huawei), Pierre Peloso (Nokia).

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

Michael H. Behringer (editor)

Email: Michael.H.Behringer@gmail.com

Brian Carpenter

School of Computer Science

University of Auckland

PB 92019

Auckland 1142

New Zealand

Email: brian.e.carpenter@gmail.com

Toerless Eckert

Futurewei USA

2330 Central Expy

Santa Clara, CA 95050

United States of America

Email: tte+ietf@cs.fau.de

Laurent Ciavaglia

Nokia

Villarceaux

91460 Nozay

France

Email: laurent.ciavaglia@nokia.com

Jéferson Campos Nobre

Federal University of Rio Grande do Sul (UFRGS)

Av. Bento Gonçalves, 9500

Porto Alegre-RS

91501-970

Brazil

Email: jcnobre@inf.ufrgs.br


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

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

nmalykh@protokols.ru

1В переводе используется принятая в русском языке терминология для автоматических и автоматизированных узлов (систем, элементов). Автоматическая система работает без привлечения человека или внешней системы управления, автоматизированная просто выполняет задание (сценарий), заданный человеком или внешней системой управления. Термин «самоуправляемый» в переводе используется как синоним термина «автоматический». Прим. перев.

2Application programming interface – интерфейс с прикладными программами.

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

Спецификация языка P4_16, версия 1.2.2

image_print

Спецификация языка P416, версия 1.2.2

The P416 Language Specification version 1.2.2

The P4 Language Consortium

2021-05-17

PDF

Аннотация

P4 – язык программирования для уровня данных сетевых устройств. В этом документе приведено точное определение языка P416, который является результатом пересмотра в 2016 г. языка P4 (http://p4.org). Документ предназначен для разработчиков, создающих компиляторы, имитаторы, среды разработки (IDE) и отладчики для программ P4. Документ может также быть интересен программистам P4, желающим более глубоко понять синтаксис и семантику языка.

Оглавление

Исключено в версии HTPL

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. Обзор

P4 представляет собой язык, описывающий обработку пакетов в плоскости данных программируемого элемента пересылки, такого как программный или аппаратный коммутатор, сетевой адаптер, маршрутизатор или специализированная сетевая платформа. Имя P4 возникло из названия статьи, где язык был предложен – «Programming Protocol-independent Packet Processors»1. Хотя P4 изначально был предназначен для программируемых коммутаторов, область его применения расширилась и сейчас охватывает широкий спектр устройств. В оставшейся части документа такие устройствами будут называться целевыми платформами или целями (target).


Рисунок 1. Традиционные и программируемые коммутаторы.

Многие платформы реализуют плоскости данных и управления. Язык 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. Идентификатор typeRef (см. выше) должен указывать один из следующих типов:

  • целое число без знака, т. е. bit<W> с неким постоянным W;

  • целое число со знаком, т. е. int<W> с неким постоянным W;

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

Например, объявление

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

Выражение для инициализации (initializer) должно быть известно в момент компиляции. Аннотации, представляемые нетерминальными optAnnotations, описаны в разделе 18. Аннотации, операции со значениями enum – в параграфе 8.3. Операции над типом enum.

7.2.2. Типы заголовков

Для определения типа header применяется показанный ниже синтаксис.

headerTypeDeclaration
	: optAnnotations HEADER name '{' structFieldList '}'
	;

structFieldList
	: /* пусто */
	| structFieldList structField
	;

structField
	: optAnnotations typeRef name ';'
	;

где каждое в качестве typeRef можно применять строки битов (переменного или фиксированного размера), целые числами фиксированного размера со знаком, логический тип или struct (с полями типа struct) с произвольной вложенностью, если все типы «листьев» относятся к bit<W>, int<W>, сериализуемым enum или bool. При использовании bool внутри заголовка P4, все реализации кодируют bool однобитовым полем, где 1 представляет true, а 0 – false.

Объявление заголовка вводит новый идентификатор в текущей области действия, который можно указывать заданным идентификатором типа. Заголовок похож на структуру 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 «форсирование» поддерживается лишь для функций и методов – в одной области действия может существовать множество одноимённых методов. При использовании форсирования компилятор должен быть способен устранить неоднозначности вызова методов и функций по числу или именам аргументов. Типы аргументов при устранении неоднозначностей не рассматриваются.

Абстрактные методы

Типовые методы объектов extern являются встроенными и реализуются целевой архитектурой. Программы P4 могут лишь вызывать такие методы.

Однако некоторые типы объектов extern могут предоставлять методы, которые можно реализовать в программе P4. Такие методы описываются с помощью ключевого слова abstract перед определением метода.

extern Balancer {     Balancer();
     // Определение числа активных потоков     bit<32> getFlowCount();
     // Возвращает индекс порта для балансировки нагрузки
     // @param address: Адрес IPv4 для источника потока
     abstract bit<4> on_new_flow(in bit<32> address); }

При создании экземпляра такого объекта должна быть представлена реализация всех абстрактных методов (см. 10.3.1. Ограничения для создания экземпляров на верхнем уровне).

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.

Типы struct, header, header_union и стек заголовков (header stack) также могут быть базовыми. Для использования таких базовых типов они должны быть заданы с использованием подобающих аргументов. Например,

// Базовый тип структуры
struct S<T> {
     T field;
     bool valid;
 } 

struct G<T> {
     S<T> s; 
} 
// Специализация S путём замены T на bit<32> 
const S<bit<32>> s = { field = 32w0, valid = false }; 
// Специализация G путём замены T на bit<32> 
const G<bit<32>> g = { s = { field = 0, valid = false } }; 

// generic header type 
header H<T> {
     T field; 
} 
// Специализация H путём замены T на bit<8> 
const H<bit<8>> h = { field = 1 }; 

// Стек заголовков создаётся из специализации базового типа header 
H<bit<8>>[10] stack; 

// Базовый тип header_union 
header_union HU<T> {
     H<bit<32>> h32;
     H<bit<8>>  h8;
     H<T>       ht; 
} 

// Объединение заголовков с типом, получаемым специализацией базового типа header_union 
HU<bit> hu;

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<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 };

Доступ к полям кортежа возможен с использованием синтаксиса индексов массива x[0], x[1]. Индексы должны быть константами во время компиляции, чтобы проверка типов могла статически идентифицировать поля.

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

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. Чтение неинициализированных значений и запись полей в недействительные заголовки).

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

    • int – целое число «бесконечной» точности (7.1.6.5. Целые числа “бесконечной точности”);

    • bit<W> – целое число без знака размером W битов (W >= 1, 7.1.6.2. Целые числа без знака (bit-string));

    • int<W> – целое число со знаком размером W битов (W >= 1, 7.1.6.3. Целые числа со знаком);

    • преобразованный в последовательную форму тип enum с базой bit<W> или int<W> (7.2.1. Перечисляемые типы).

  • 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 действителен
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 или другие состояния, определённые в данный момент в системе, независимо от места определения этих состояний. При выполнении любого из действий:

  • запись в поле недействительного заголовка (обычного или элемента стека с индексом в пределах диапазона), не входящего в объединение заголовков (header_union);

  • запись в элемент стека заголовков с индексом за пределами диапазона;

  • вызов метода a setValid() или setInvalid() для элемента стека заголовков с индексом за пределами диапазона

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

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

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

struct Empty {    tuple<> t; }

Ниже перечислены типы, которые считаются пустыми:

  • строки битов размером 0;
  • varbit размером 0;

  • пустые кортежи (tuple<>);

  • стеки размером 0;

  • структуры без полей;

  • кортежи, все поля которых относятся к пустым типам;

  • структуры, все поля которых относятся к пустым типам.

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

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 (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
	;

nonBraceExpression
     	: INTEGER
     	| TRUE
     	| FALSE
     	| STRING_LITERAL
     	| nonTypeName
     	| dotPrefix nonTypeName
     	| nonBraceExpression '[' expression ']'
     	| nonBraceExpression '[' expression ':' expression ']'
     	| '(' expression ')'
     	| '!' expression %prec PREFIX
     	| '~' expression %prec PREFIX
     	| '-' expression %prec PREFIX
     	| '+' expression %prec PREFIX
     	| typeName '.' member
     	| ERROR '.' member
     	| nonBraceExpression '.' member
     	| nonBraceExpression '*' expression
     	| nonBraceExpression '/' expression
     	| nonBraceExpression '%' expression
     	| nonBraceExpression '+' expression
     	| nonBraceExpression '-' expression
     	| nonBraceExpression '|+|' expression
     	| nonBraceExpression '|-|' expression
     	| nonBraceExpression '<<' expression
     	| nonBraceExpression '>>' expression
     	| nonBraceExpression '<=' expression
    	| nonBraceExpression '>=' expression
     	| nonBraceExpression '<' expression
     	| nonBraceExpression '>' expression
     	| nonBraceExpression '!=' expression
     	| nonBraceExpression '==' expression
     	| nonBraceExpression '&' expression
     	| nonBraceExpression '^' expression
     	| nonBraceExpression '|' expression
     	| nonBraceExpression '++' expression
     	| nonBraceExpression '&&' expression
     	| nonBraceExpression '||' expression
     	| nonBraceExpression '?' expression ':' expression
     	| nonBraceExpression '<' realTypeArgumentList '>' '(' argumentList ')'
     	| nonBraceExpression '(' argumentList ')'
     	| namedType '(' argumentList ')'
     	| '(' typeRef ')' expression
     	;

Выражение без скобок nonBraceExpression похоже на expression (раздел 8. Выражения), но не включает вариантов, начинающихся с левой (открывающей) скобки { для предотвращения синтаксической неоднозначности в операторах блоков.

Разрешены два типа выражений switch, описанных в двух следующих параграфах.

11.7.1 Оператор switch с выражением action_run

Выражение в операторе 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 (при наличии) должна быть последней.

11.7.2 Оператор switch с выражением целочисленного или перечисляемого типа

Для этого варианта оператора switch выражение должно давать в результате один из указанных ниже типов:

  • bit<W>;
  • int<W>;
  • enum с указанным базовым представлением или без него;
  • error.

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

// Предположим, что выражение hdr.ethernet.etherType имеет тип bit<16> 
switch (hdr.ethernet.etherType) {
    0x86dd: { /* тело опущено */ }
    0x0800:          // пропуск с переходом к следующему телу.
    0x0802: { /* тело опущено */ }
    0xcafe: { /* тело опущено */ }
    default: { /* тело опущено */ } }

11.7.3 Замечания для всех операторов switch

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

Если за меткой switch не следует оператор блока, выполняется переход к следующей метке. Однако при наличии оператора блока такого перехода не происходит. Отметим, что это отличается от операторов switch в языке C, где для предотвращения перехода в следующей метке требуется break. Если за последней меткой switch нет оператора блока, это обрабатывается как наличие пустого блока { }.

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

Если ни одна из меток не совпадает со значением выражения switch:

  • при наличии метки default
    выпол
    няется заданный по умолчанию вариант;

  • если метка default не задана, не выполняется ни один из вариантов switch и исполнение продолжается после завершения оператора switch без побочных эффектов (если их нет при вычислении выражения switch).

Обработка обобщённых операторов описана в отдельном файле.

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 '}'
	;

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

  • объявления локальных переменных;

  • операторы присваивания;

  • вызовы методов, включая:

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

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

  • условные операторы;

  • переходы в другое состояние (12.5. Операторы смены (перехода) состояния).

Синтаксис операторов для анализатора использует приведённые ниже правила.

parserStatements
	: /* пусто */
	| parserStatements parserStatement
	;
parserStatement
	: assignmentOrMethodCallStatement
	| directApplication
	| variableDeclaration
	| constantDeclaration
	| parserBlockStatement
	| emptyStatement
	| conditionalStatement
	;
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 или _ не используются. Компилятор в таких случаях должен выдавать предупреждение. Это показывает важное различие между выражениями 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_set принимает в качестве параметра типа 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 может выть выражен