コンテンツにスキップ

15. Parameterization

In order to support libraries of useful P4 components, both parsers and control blocks can be additionally parameterized through the use of constructor parameters.

  • Consider again the parser declaration syntax:
    Begin P4Grammar [INCLUDE=grammar.mdk:parserDeclaration]

  • [INCLUDE=grammar.mdk:optConstructorParameters]
    End P4Grammar

From this grammar fragment we infer that a parser declaration may have two sets of parameters:

  • The runtime parser parameters (parameterList)
  • Optional parser constructor parameters (optConstructorParameters)

Constructor parameters must be directionless (i.e., they cannot be in, out, or inout) and where the parser is instantiated, it must be possible to fully evaluate the expressions supplied for these parameters at compilation time.

  • Consider the following example:
    Begin P4Example parser GenericParser(packet_in b, out Packet_header p) (bool udpSupport) { // constructor parameters state start { b.extract(p.ethernet); transition select(p.ethernet.etherType) { 16w0x0800: ipv4; } } state ipv4 { b.extract(p.ipv4); transition select(p.ipv4.protocol) { 6: tcp; 17: tryudp; } } state tryudp { transition select(udpSupport) { false: accept; true : udp; } } state udp { // body omitted } }

    End P4Example

When instantiating the GenericParser it is necessary to supply a value for the udpSupport parameter, as in the following example:

\~ Begin P4Example // topParser is a GenericParser where udpSupport = false GenericParser(false) topParser; \~ End P4Example

Controls and parsers are often instantiated exactly once. As a light syntactic sugar, control and parser declarations with no constructor parameters may be applied directly, as if they were an instance. This has the effect of creating and applying a local instance of that type.

\~ Begin P4Example control Callee(/* parameters omitted /) { / body omitted */ }

control Caller(/* parameters omitted /)(/ parameters omitted /) { apply { Callee.apply(/ arguments omitted */); // Callee is treated as an instance } } \~ End P4Example

  • The definition of Caller is equivalent to the following.
    Begin P4Example control Caller(/* parameters omitted /)(/ parameters omitted /) { @name(“Callee”) Callee() Callee_inst; // local instance of Callee apply { Callee_inst.apply(/ arguments omitted */); // Callee_inst is applied } }

    End P4Example

    Begin P4Grammar [INCLUDE=grammar.mdk:directApplication]

    End P4Grammar

This feature is intended to streamline the common case where a type is instantiated exactly once.

The second production in the grammar allows direct calls for generic controls or parsers:

\~ Begin P4Example control Callee(/* parameters omitted /) { / body omitted */ }

control Caller(/* parameters omitted /)(/ parameters omitted /) { apply { // Callee\<bit\<32>> is treated as an instance Callee\<bit\<32>>.apply(/ arguments omitted */); } } \~ End P4Example

For completeness, the behavior of directly invoking the same type more than once is defined as follows.

  • Direct type invocation in different scopes will result in different local instances with different fully-qualified control names.
  • In the same scope, direct type invocation will result in a different local instance per invocation—however, instances of the same type will share the same global name, via the @name annotation. If the type contains controllable entities, then invoking it directly more than once in the same scope is illegal, because it will produce multiple controllable entities with the same fully-qualified control name.

See Section [#sec-name-annotations] for details of @name annotations.

No direct invocation is possible for controls or parsers that require constructor arguments. These need to be instantiated before they are invoked.