P416 Language Specification
The P4.org language consortium
December 16, 2016

Abstract. P4 is a language for programming the data plane of network devices. This document provides a precise definition of the P416 language, which is the 2016 revision of the P4 language http://​p4.​org. The primary target audience for this document includes developers who want to write compilers/simulators/IDEs/debuggers for P4 programs. This document may also be useful for P4 programmers who are interested in understanding the language syntax and semantics at a deeper level.

1. Scope

This specification establishes the form and interpretation of programs, written in the P416 programming language. It specifies:

This specification does not specify:

2. Terms, definitions and symbols

Throughout this specification, the following terms will be used. Terms, explicitly defined in this specification are not to be presumed to refer implicitly to the similar terms, defined elsewhere. Terms, not explicitly defined in this specification should be interpreted according to ISO/IEC 2382:2015 (Information Technology - Vocabulary) or the other generally recognizable sources, such as RFCs.

3. Overview


Figure 1. Traditional switches vs. programmable switches.

P4 is a language for expressing how packets are processed by the data plane of a programmable network forwarding element such as a programmable hardware or software switch, network interface card, router or network function appliance. The name comes from the original paper that introduced the language, “Programming Protocol-independent Packet Processors,” https://​arxiv.​org/​pdf/​1312.​1719.​pdf. While initially P4 was designed for programming network switches, its scope has been broadened to cover a large variety of packet processing systems. In the rest of this document we use the generic term target for all such network processing system devices.

Many target devices contain both a control plane and a data plane. P4 is designed to specify only the target data plane functionality. P4 programs also partially define the interface by which the control plane and the data-plane communicate, but P4 cannot be used to describe the target's control-plane functionality. In the rest of this document, when we talk about P4 as “programming a target”, we mean “programming the target data plane”.

As a concrete example in the context or programming network switches, Figure 1 illustrates the difference between a traditional fixed-function switch and a P4-programmable switch. In a traditional switch the manufacturer defines the data-plane functionality. The control-plane controls the data plane by managing entries in tables (e.g.routing tables), configuring specialized objects (e.g.meters) and by processing control-packets (e.g.routing protocol packets) or asynchronous events, such as link state changes or learning notifications.

A P4-programmable switch differs from a traditional switch in two ways:

Hence, P4 itself is protocol independent but allows programmers to express a rich set of data plane behaviors and protocols.


Figure 2. Programming a target with P4.

The core abstractions provided by the P4 language are:

Figure 2 shows a typical tool workflow when programming a target using P4.

Target manufacturers provide the hardware or software implementation framework, an architecture definition, and a P4 compiler for that target. P4 programmers write programs in P4 for a specific architecture. The architecture defines a set of P4-programmable components on the target as well as their external data plane interfaces.

Compiling a set of P4 programs produces two artifacts:

P4 is a domain-specific language. It is designed to be implementable on a large variety of target platforms such as programmable network cards, FPGA switches, software switches and programmable ASICs. As such the language is restricted to constructs that are efficiently implementable on all these platforms.

P4 is not a Turing-complete language. In fact, assuming a fixed cost for a table lookup operation, all P4 program blocks (i.e., parser or control) should provably execute a constant O(1) number of operations for each byte of an input packet received (i.e., each header byte analyzed). In other words, the computational complexity of a P4 program depends linearly only on the header sizes, and never depends on the size of the state accumulated while processing data (e.g., the number of flows, or the total number of packets processed). These guarantees are necessary (but not sufficient) for enabling fast packet processing across a variety of targets.

P4 conformance of a target is defined as follows: if a specific target T supports only a subset of the P4 programming language (let's call it P4T), the programs written in P4T executed on the target should provide the exact same behavior as P4 programs executed on the P4 abstract machine in this document.

Note that P4 conformant targets can provide arbitrary P4 language extensions and extern elements.

3.1. Benefits of P4

Compared to the state-of-the-art method of programming network processing systems (e.g., writing microcode on top of custom hardware), P4 provides significant advantages:

3.2. P4 language evolution: comparison to previous versions (P4 v1.0/v1.1)


Figure 3. Evolution of the language between versions P414 (versions 1.0 and 1.1) and P416.

The P4 language went through some significant, backwards-incompatible changes to the language syntax and semantics. The language evolution between the previous version (P414) the the current one (P416) is illustrated in Figure 3. In particular, a significant number of language constructs have been eliminated from the language and will be migrated into libraries. Examples include: counters, checksum units, meters, etc.

The original complex language (74 keywords) has been thus transformed into a relatively small core language (35 keywords, shown in Section A) accompanied by a core library of fundamental constructs which are necessary for writing almost all P4 programs. This core language is the subject of this specification.

The v1.1 version of P4 introduced a language construct called extern which can be used to describe library elements. Many constructs that are defined in the v1.1 language specification will thus be transformed into such library elements (including equivalents to v1.1 constructs that have been eliminated from the language, such as counters and meters). Some of these extern objects are expected to be standardized, and they will be in the scope of a separate document, describing a standard library of P4 elements. In this document we provide several examples of extern constructs.

The P416 language also introduces and repurposes some v1.1 language constructs for describing the programmable parts of an architecture. These language constructs are: parser, state, control, and package.

One important goal of the P416 language revision is to provide a stable programming language definition, that promotes backwards-compatibility. In other words, we strive for programs written in P416 to remain syntactically correct and to behave identically when treated as programs later versions.

4. Architecture Model

4.1. The architecture


Figure 4. P4 program interfaces.

The P4 architecture identifies the P4-programmable blocks (e.g., parser, ingress pipeline, egress pipeline, deparser, etc.) and their data plane interfaces.

The P4 architecture can be thought of as a contract between the target and P4 code, executing on it. Each target manufacturer must therefore provide both the P4 compiler for it as well as an accompanying architecture definition for their target. (We expect that P4 compilers for all architectures can share a common front-end). This architecture definition does not have to expose the entire programmable surface of the data plane a manufacturer may even choose to provide multiple definitions for the same hardware device, each with different capabilities (e.g., with or without multicast support).

Figure 4 illustrates the data plane interfaces of P4 programs. It shows a target that has two programmable blocks (#1 and #2). Each block is programmed through a dedicated P4 program fragment. The target interfaces with the P4 program through a set of control registers or signals. Input controls provide information to P4 programs (e.g., the input port that a packet was received from), while output controls can be written to by P4 programs to influence the target behavior (e.g., the output port where a packet has to be directed). Control registers/signals are represented in P4 by intrinsic metadata.

Moreover, P4 programs can store and manipulate data pertaining to each packet, represented by user-defined metadata.

The behavior of each P4 program is completely described as a set of transformations mapping vectors of bits to vectors of bits. However, only the architecture model attaches a meaning to the bits in a control register. For example, in order to cause a network packet to be forwarded on a specific output port, a P4 program may need to write the output port index into a dedicated control register. Similarly, in order to cause a packet to be dropped, a P4 program may need to set a “drop” bit into another dedicated control register.


Figure 5. P4 program invoking the services of a fixed-function object.

P4 programs can invoke services of fixed-function blocks. Figure 5 shows a P4 program invoking the services of a target built-in checksum computation unit. The implementation of the checksum unit is not specified in P4, but its interface is. Interfaces (represented by P4 extern objects) describe the set of operations that are offered by a fixed-function object as well as their arguments, similar to methods in object-oriented programming languages.

In general, P4 programs are not expected to be portable across different architectures. For example, executing a P4 program that controls packet broadcast by writing into a custom control register will not work on a target that provides no such control register. However, P4 programs written for a given architecture should be portable across all targets that faithfully implement the corresponding model (assuming that enough resources are available to implement the program).

4.2. The P4 standard architecture

We expect that the P4 community will evolve a standard architecture model (or a small set of models, pertaining to specific verticals, e.g., switches and network cards). Wide adoption of such standard architectures should promote wide portability of P4 programs. The standard architecture is the scope of a separate document.

4.3. P4 program data plane interfaces

(In the following examples P4 keywords are highlighted in fixed-size fonts, e.g., parser.) To describe a functional block that can be programmed in P4 the target manufacturer provides a target type declaration. Target declarations are discussed in in Section 15, but we give a brief introduction here to make things concrete. For example, the target manufacturer could write a declaration as follows:

control matchActionPipe<H>(in bit<4> inputPort,
                           inout H parsedHeaders,
                           out bit<4> outputPort);

This declaration describes a programmable block named matchActionPipe that performs match-action processing (shown by the control P4 reserved keyword). The interface between the matchActionPipe block and the surrounding hardware can be read from this declaration:

4.4. External units with predefined functionality

P4 programs can also interact with fixed-function objects by invoking their services. Such fixed-function objects are described using the extern object construct, which only describes the interfaces that such an object exposes to the data-plane; a complete description of extern is given in Section 7.2.7, but we provide an overview here.

extern objects are similar to pure abstract classes from object-oriented programming (or interfaces in Java and C#), by describing a set of methods that are implemented by an object, but not the implementation of these methods. For example, the following construct could be used to describe the operations offered by an incremental checksum unit:

extern Checksum16 {
    void clear();           // prepare unit for computation
    void update<T>(T data); // add data to checksum
    void remove<T>(T data); // remove data from existing checksum
    bit<16> get(); // get the checksum for the data added since last clear

5. Example: A very simple switch

To make the discussion concrete we begin by presenting a complete example: we start by describing the architecture of a very simple switch. We then provide the P4 description of the architecture. We end by writing a complete P4 program for controlling the switch. While the example is relatively involved, it makes use all important features of the P4 programming language.