[P4-dev] Parse/process dynamic payload

Andy Fingerhut andy.fingerhut at gmail.com
Mon Oct 8 11:47:22 EDT 2018

In a P4 parser, whenever you call extract() on a fixed length header with N
bytes, it checks whether there are N bytes remaining in the packet, or
more.  If there are, the extract succeeds, and the header .isValid()
becomes true.  If there are not, the parser records a PacketTooShort error,
and .isValid() for that header remains false.

In simple_switch, all fields of such a header on which extract failed will
be 0.  FYI, on other P4 targets, the contents of those header fields could
be undefined garbage rather than predictable 0 values like you get from

You could modify your parser in these ways to get results probably closer
to what you were hoping for:

+ change your definition of the TCP header to remove the 2 bytes at the end
that are part of the payload, which as you mention some packets may not have
+ create a new header with those payload bytes, e.g. payload_t
+ Change your parse state for parsing the TCP header so that after it
extracts the TCP header, it calculates the length of the TCP payload in
bytes, e.g. meta.tcp_payload_len = (hdr.ipv4.totalLen - IPV4_LEN -
((bit<16>) hdr.tcp.dataOffset << 4));

Then do a transition select statement on the value of
meta.tcp_payload_len.  The select expression should have cases of 0 or 1
that transition to accept, and a default case that transitions to a new
parse state that extracts the new payload header.  With the suggested logic
above, it will only transition to that parse state if there are at least 2
bytes of TCP payload data in the packet.  If there are not, that new header
you defined for the 2 bytes of payload should have .isValid() false when
parsing is complete.

I don't know how important it is to you to get this correct, but your TCP
header has a fixed length 96-bit field for TCP options.  If you want the
new payload field to never include TCP option data, you should change the
definition of that options field to be `varbit` instead of `bit`, and do a
variable length extract() call in your TCP parsing state to calculate the
length of the options.


On Mon, Oct 8, 2018 at 5:21 AM cs.lev <cs.lev at gmx.com> wrote:

> Hi all,
> I am (still) playing with P4's capability to modify/monitor the payload
> in a packet. According to some sources I have found here and on the
> github, I quickly created a simple P4 application that prints out the
> processed packet's data, i.e., header information from layer 2 to layer
> 4.
> Source code is here:
> https://github.com/cslev/p4debug
> Logging is based on debug tables and exact matches on the different
> fields of the header.
> (debug tables can be enabled by `#define` conditions in the beginning
> of the source code - now IP/TCP is enabled for ingress processing.
> I have encountered that if I further define a couple of bytes to parse
> in the header, i.e., when I read the payload, for instance, 2 bytes
> after the TCP options field, I became able to match on those specific
> bytes as well.
> However, if the payload is shorter than 2-bytes, the whole packet and
> its headers are treated as a corrupted packet and monitoring (or even a
> TCP header based routing) is not working.
> In particular, assume I have a TCP netcat connection between two hosts,
> and the client sends two characters, say, two 'a' (which is 2 bytes + 1
> byte EOL character) then parsing is working well and I can see the
> following in the console:
> * standard_metadata.ingress_port: 0000
> * meta.tcp_metadata.tcp_len     : 0029
> * hdr.tcp.srcPort               : da2e
> * hdr.tcp.dstPort               : 115c
> * hdr.tcp.seqNo                 : 76dc4b4b
> * hdr.tcp.ackNo                 : 8dcbb939
> * hdr.tcp.dataOffset            : 08
> * hdr.tcp.flags_1               : 00
> * hdr.tcp.flags_2               : 01
> * hdr.tcp.flags_3               : 08
> * hdr.tcp.window                : 00e5
> * hdr.tcp.checksum              : 5ffa
> * hdr.tcp.urgentPtr             : 0000
> * hdr.tcp.payload               : 6161
> However, if I only send an empty character with the 1-byte EOL
> character (0x0a) summing up only 1-byte payload, then not just the
> payload parsing "crashes in some sense" but I get the following output:
> * standard_metadata.ingress_port: 0000
> * meta.tcp_metadata.tcp_len     : 0000
> * hdr.tcp.srcPort               : 0000
> * hdr.tcp.dstPort               : 0000
> * hdr.tcp.seqNo                 : 00000000
> * hdr.tcp.ackNo                 : 00000000
> * hdr.tcp.dataOffset            : 00
> * hdr.tcp.flags_1               : 00
> * hdr.tcp.flags_2               : 00
> * hdr.tcp.flags_3               : 00
> * hdr.tcp.window                : 0000
> * hdr.tcp.checksum              : 0000
> * hdr.tcp.urgentPtr             : 0000
> * hdr.tcp.payload               : 0000
> Of course, this always happens for the ACK messages back from the
> server as there is no payload at all.
> Furthermore, hdr.tcp.isValid() function also fails - I guess because it
> validates the header according to my specification, which should
> contain the 2-byte big payload as well.
> I can overcome this by having a condition on the ipv4.protocol field
> instead if I want to catch TCP packets, but still the TCP header
> information in the debug tables show zeros.
> Is there any way to overcome this?
> Maybe putting payload related part into metadata and parse that part
> with lookahead() functions? Would it even work with dynamic payload
> length?
> Thanks,
> cs.lev
> _______________________________________________
> P4-dev mailing list
> P4-dev at lists.p4.org
> http://lists.p4.org/mailman/listinfo/p4-dev_lists.p4.org
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.p4.org/pipermail/p4-dev_lists.p4.org/attachments/20181008/1146bad5/attachment-0001.html>

More information about the P4-dev mailing list