20. Annotations
Annotations are a simple mechanism for extending the P4 language to some
limited degree without changing the grammar. Annotations are attached to
types, fields, variables, etc. using the @ syntax (as shown explicitly
in the P4 grammar). Unstructured annotations, or just “annotations,”
have an optional body; structured annotations have a mandatory body,
containing at least a pair of square brackets [].
\~ Begin P4Grammar [INCLUDE=grammar.mdk:optAnnotations]
[INCLUDE=grammar.mdk:annotations]
- [INCLUDE=grammar.mdk:annotation]
End P4Grammar
Structured annotations and unstructured annotations on any one element
must not use the same name. Thus, a given name can only be applied
to one type of annotation or the other for any one element. An
annotation used on one element does not affect the annotation on another
because they have different scope.
-
This is legal:
Begin P4Example @my_anno(1) table T { /* body omitted / } @my_anno [2] table U { / body omitted */ } // OK - different scope than previous // use of my_annoEnd P4Example
-
This is illegal:
Begin P4Example @my_anno(1) @my_anno [2] table U { /* body omitted */ } // Error - changed type of anno // on an elementEnd P4Example
Multiple unstructured annotations using the same name can appear on a
given element; they are cumulative. Each one will be bound to that
element. In contrast, only one structured annotation using a given
name may appear on an element; multiple uses of the same name will
produce an error.
-
This is legal:
Begin P4Example @my_anno(1) @my_anno(2) table U { /* body omitted */ } // OK - unstructured annos accumulateEnd P4Example
-
This is illegal:
Begin P4Example @my_anno [1] @my_anno [2] table U { /* body omitted */ } // Error - reused the same structured // anno on an elementEnd P4Example
The flexibility of P4 unstructured annotations comes from the minimal
structure mandated by the P4 grammar: unstructured annotation bodies may
contain any sequence of terminals, so long as parentheses are balanced.
In the following grammar fragment, the annotationToken non-terminal
represents any terminal produced by the lexer, including keywords,
identifiers, string and integer literals, and symbols, but excluding
parentheses.
\~ Begin P4Grammar [INCLUDE=grammar.mdk:annotationBody] \~ End P4Grammar
Unstructured annotations may impose additional structure on their
bodies, and are not confined to the P4 language. For example, the
P4Runtime specification[8] defines a @pkginfo annotation that
expects key-value pairs.
Unlike unstructured annotations, structured annotations use square
brackets [...] and have a restricted format. They are commonly used to
declare custom metadata, consisting of expression lists or key-value
lists but not both. An expressionList may be empty or contain a
comma-separated list of member expressions. A kvList consists of one
or more kvPairs, each consisting of a key and a value expression.
Note the syntax for expression is rich, see Appendix [#sec-grammar]
for details.
All expressions within a structuredAnnotationBody must be
compile-time known values with a result type that is either: string,
int, or bool. In particular, structured expressions (e.g. an
expression containing an expressionList, a kvList, etc.) are not
allowed. Note that P4Runtime information (P4Info) may stipulate
additional restrictions. For example, an integer expression might be
limited to 64-bit values.
It is illegal to duplicate a key within the kvList of a structured
annotation.
\~ Begin P4Grammar [INCLUDE=grammar.mdk:structuredAnnotationBody] … [INCLUDE=grammar.mdk:expressionList] … [INCLUDE=grammar.mdk:kvList]
- [INCLUDE=grammar.mdk:kvPair]
End P4Grammar
Structured Annotation Examples
Empty Expression List
-
The following example produces an empty annotation:
Begin P4Example @Empty [] table t { /* body omitted */ }End P4Example
Mixed Expression List
The following example will produce an effective expression list as follows:
[1,"hello",true, false, 11]
\~ Begin P4Example #define TEXT_CONST “hello” #define NUM_CONST 6 @MixedExprList [1,TEXT_CONST,true,1==2,5+NUM_CONST] table t { /* body omitted */ } \~ End P4Example
-
kvList of Strings
Begin P4Example @Labels [short="Short Label", hover="My Longer Table Label to appear in hover-help"] table t { /* body omitted */ }End P4Example
kvList of Mixed Expressions
The following example will produce an effective kvList as follows.
[label="text", my_bool=true, int_val=6]
\~ Begin P4Example @MixedKV[label=“text”, my_bool=true, int_val=2*3] table t { /* body omitted */ } \~ End P4Example
Illegal Mixing of kvPair and expressionList
The following example is invalid because the body contains both a
kvPair and an expression:
\~ Begin P4Example @IllegalMixing [key=4, 5] // illegal mixing table t { /* body omitted */ } \~ End P4Example
Illegal Duplicate Key
-
The following example is invalid because the same key occurs more than once:
Begin P4Example @DupKey [k1=4,k1=5] // illegal duplicate key table t { /* body omitted */ }End P4Example
Illegal Duplicate Structured Annotation
The following example is invalid because the annotation name occurs
more than once on the same element, e.g. table t:
\~ Begin P4Example @DupAnno [k1=4] @DupAnno [k2=5] // illegal duplicate name table t { /* body omitted */ } \~ End P4Example
Illegal Simultaneous Use of Both Structured and Unstructured Annotation
The following example is invalid because the annotation name is used
by both an unstructured and structured annotation on the same element
table t:
\~ Begin P4Example @MixAnno(“Anything”) @MixAnno [k2=5] // illegal use in both annotation types table t { /* body omitted */ } \~ End P4Example
Annotation names that start with lowercase letters are reserved for the
standard library and architecture. This document pre-defines a set of
“standard” annotations in Appendix [#sec-p4-reserved-annotations].
We expect that this list will grow. We encourage custom architectures to
define annotations starting with a manufacturer prefix: e.g., an
organization named X would use annotations named like @X_annotation
Optional parameter annotations
A parameter to a package, parser type, control type, extern method,
extern function or extern object constructor can be annotated with
@optional to indicate that the user does not need to provide a
corresponding argument for that parameter. The meaning of a parameter
with no supplied value is target-dependent.
Annotations on the table action list
The following two annotations can be used to give additional information to the compiler and control-plane about actions in a table. These annotations have no bodies.
@tableonly: actions with this annotation can only appear within the table, and never as default action.@defaultonly: actions with this annotation can only appear in the default action, and never in the table.
\~ Begin P4Example table t { actions = { a, // can appear anywhere @tableonly b, // can only appear in the table @defaultonly c, // can only appear in the default action } /* body omitted */ } \~ End P4Example
Control-plane API annotations
The @name annotation directs the compiler to use a different local
name when generating the external APIs used to manipulate a language
element from the control plane. This annotation takes a string literal
body. In the following example, the fully-qualified name of the table is
c_inst.t1.
\~ Begin P4Example control c( /* parameters omitted / )() { @name(“t1”) table t { / body omitted / } apply { / body omitted */ } } c() c_inst; \~ End P4Example
The @hidden annotation hides a controllable entity, e.g. a table, key,
action, or extern, from the control plane. This effectively removes its
fully-qualified name (Section [#sec-cp-names]). This annotation does
not have a body.
Restrictions
Each element may be annotated with at most one @name or @hidden
annotation, and each control plane name must refer to at most one
controllable entity. This is of special concern when using an absolute
@name annotation: if a type containing a @name annotation with an
absolute pathname (i.e., one starting with a dot) is instantiated more
than once, it will result in the same name referring to two controllable
entities.
\~ Begin P4Example control noargs(); package top(noargs c1, noargs c2);
control c() { @name(“.foo.bar”) table t { /* body omitted / } apply { / body omitted */ } } top(c(), c()) main; \~ End P4Example
Without the @name annotation, this program would produce two
controllable entities with fully-qualified names main.c1.t and
main.c2.t. However, the @name(".foo.bar") annotation renames table
t in both instances to foo.bar, resulting in one name that refers to
two controllable entities, which is illegal.
Concurrency control annotations
The @atomic annotation, described in Section [#sec-concurrency] can
be used to enforce the atomic execution of a code block.
Value set annotations
The @match annotation, described in Section [#sec-select], is used
to specify a match_kind value other than the default match_kind of
exact for a field of a value_set.
Extern function/method annotations
Various annotations may appear on extern function and method declarations to describe limitations on the behavior and interactions of those functions. By default extern functions might have any effect on the environment of the P4 program and might interact in non-trivial ways (subject to a few limitations – see section [#sec-calling-convention-justification]). Since externs are architecture-specific and their behavior is known to the architecture definition, these annotations are not strictly necessary (an implementation can have knowledge of how externs interact based on their names built into it), but these annotations provide a uniform way of describing certain well-defined interactions (or their absence), allowing architecture-independent analysis of P4 programs.
-
@pure- Describes a function that depends solely on itsinparameter values, and has no effect other than returning a value, and copy-out behavior on itsoutandinoutparameters. No hidden state is recorded between calls, and its value does not depend on any hidden state that may be changed by other calls. An example is ahashfunction that computes a deterministic hash of its arguments, and its return value does not depend upon any control-plane writable seed or initialization vector value. A@purefunction whose results are unused may be safely eliminated with no adverse effects, and multiple calls with identical arguments may be combined into a single call (subject to the limits imposed by copy-out behavior ofoutandinoutparameters).@purefunctions may also be reordered with respect to other computations that are not data dependent. -
@noSideEffects- Weaker than@pureand describes a function that does not change any hidden state, but may depend on hidden state. One example is ahashfunction that computes a deterministic hash of its arguments, plus some internal state that can be modified via control plane API calls such as a seed or initialization vector. Another example is a read of one element of a register array extern object. Such a function may be dead code eliminated, and may be reordered or combined with other@noSideEffectsor@purecalls (subject to the limits imposed by copy-out behavior ofoutandinoutparameters), but not with other function calls that may have side effects that affect the function.
Deprecated annotation
The deprecated annotation has a required string argument that is a
message that will be printed by a compiler when a program is using the
deprecated construct. This is mostly useful for annotating library
constructs, such as externs.
\~ Begin P4Example @deprecated(“Please use the ‘check’ function instead”) extern Checker { /* body omitted */ } \~ End P4Example
No warnings annotation
The noWarn annotation has a required string argument that indicates a
compiler warning that will be inhibited. For example @noWarn("unused")
on a declaration will prevent a compiler warning if that declaration is
not used.
Each P4 compiler implementation can define additional annotations specific to the target of the compiler. The syntax of the annotations should conform to the above description. The semantics of such annotations is target-specific. They could be used in a similar way to pragmas in other languages.
The P4 compiler should provide:
- Errors when annotations are used incorrectly (e.g., an annotation expecting a parameter but used without arguments, or with arguments of the wrong type)
- Warnings for unknown annotations.