What happens when extracting from an invalid header in bmv2?

Hi there,

Assume there is a p4 program that first parse ethernet header and then ipv4 header, and here is the header structure:

header ethernet_t {
    macAddr_t dstAddr;
    macAddr_t srcAddr;
    bit<16>   etherType;
}

header ipv4_t {
    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;
    ip4Addr_t srcAddr;
    ip4Addr_t dstAddr;
}

struct headers {
    ethernet_t   ethernet;
    ipv4_t       ipv4;
}

And what happens when a pkt that is too short, like it contains a valid ethernet header, but not enough bits to extract a ipv4 header. What are those ipv4 fields after the extraction process? Like srcAddr, dstAddr and, ihl? Are they all 0 if the packet is too short?

parser MyParser( packet_in packet,
                 out headers hdr,
                 inout metadata meta,
                 inout standard_metadata_t standard_metadata ) {

    state start {
        transition parse_ethernet;
    }

    state parse_ethernet {
        packet.extract( hdr.ethernet );
        transition select( hdr.ethernet.etherType ) {
            TYPE_IPV4: parse_ipv4;
            default: accept;
        }
    }

    state parse_ipv4 {
        packet.extract( hdr.ipv4 );
        transition accept;
    }
}

regards,

The P4 language specification says that when parsing such a packet, that contains enough bytes for a full Ethernet header, but not enough additional bytes to include a full IPv4 header, the parser you should do the following:

  • in state parse_ethernet, packet.extract(hdr.ethernet) will execute normally, leaving hdr.ethernet.isValid() equal to true, and all fields of hdr.ethernet equal to a copy of the corresponding bits from the parsed packet.

  • then assuming that hdr.ethernet.etherType is equal to TYPE_IPV4, the parser will transition to state parse_ipv4, where it will execute packet.extract(hdr.ipv4). Because there are not enough bytes to completely fill all of the fields of hdr.ipv4, parsing will immediately end, without executing any following statements, including not the “transition accept” line in state parse_ipv4. hdr.ipv4.isValid() will be false. The parser will transition to the special state “reject” and stop execution immediately.

Note that just because the parser transitions to state reject does not automatically mean that the packet will be dropped. In many P4 architectures, including v1model, PSA, and PNA, it is defined that the packet will be processed by the following control. If the developer wishes the packet to be dropped always if they experience a parse error, they should check the error status from the parser to see if it indicates a parsing error occurred, and drop the packet.

The P4 language spec says that if you attempt to use the value of a field within a header that is currently invalid, then an implementation is allowed to give back unpredictable values. e.g. hdr.ipv4.ihl might be 7 when you use it in one expression, and in the very next line of code if you use hdr.ipv4.ihl again it might be 1. A particular P4 implementation might behave in a more predictable way, if the implementers choose, but the language spec does not require them to be more predictable.

Hi andyfingerhut,

Thanks for your detailed explanation, that would answer my question. And also you mentioned that the answer is somehow mentioned in the p4 language specification,, but I was overwhelmed by its content and had no idea of how to find the solution. So do you have any suggestions based on your experience?

regards.

My first suggestion would be: Write your P4 code so that its behavior does not depend upon the values of fields in invalid headers :slight_smile:

Were you looking for other suggestions?

No, thanks for your suggestion!

Just a small note: if you are really using Ethernet, then there is no way that the packet will be too short in your particular case. The minimum Ethernet frame size is 60 bytes plus 4 bytes of FCS, whereas the combined size of the Ethernet header plus IPv4 header is 34 bytes. :slight_smile:

Thanks for your friendly note! Have a nice thanksgiving holiday!