[P4-dev] Encapsulation of variable-length headers

Vladimir Gurevich vladimir.gurevich at barefootnetworks.com
Sat Sep 22 09:33:45 EDT 2018


Hello Cristina,

Glad to hear it helped.

In terms of whether to use multiple instances of the header of the same
type versus a stack, the answer would depend on the actual hardware.

In general, a stack of headers would be more expensive, since it allows you
to perform push and pop operations. Therefore, if you do not plan to use
those, multiple individual headers might be better. Same thing is true in C
, for example: when you allocate an array, the compiler needs to allocate
its elements consecutively, as one block of memory, while if you declare
individual variables, they can go anywhere. We do not think much about
those details nowadays with gigabytes of RAM at our disposal, but high
speed switching devices are different in that respect.

Happy hacking,
Vladimir

On Sat, Sep 22, 2018, 3:04 AM <cristina.dominicini at aluno.ufes.br> wrote:

>
> Dear Vladimir and Andy,
>
> Thank you very much for the insights!
>
> Following your suggestions, I created one action per number of hops, and
> it works like a charm :-)
>
> Andy, it was not necessary to create a different header for each case
> (srcRoute_partn), I used hdr.srcRoutes[n].setValid() inside actions.
>
> Best regards,
> Cristina
>
>
> Em 21.09.2018 02:51, Andy Fingerhut escreveu:
>
> Cristina:
>
> I may have missed this in your message, but in case it was not already
> obvious to you, there is no need for a P4_16 'header' type to correspond
> with one header in an RFC document.  It is often written this way in P4
> programs, but P4 doesn't care.
>
> If it helps to have h1_part1, h1_part2, h1_part3, etc., each of which
> contains only fixed length fields, and write encapsulation code that calls
> setValid() on only the parts you need, and emit() all of them in the
> deparser, then only the ones you make valid will be added to the outgoing
> packet.
>
> I think Vladimir already suggested this, but you can also have N different
> sizes of fixed length header, e.g. for the IPv6 Routing extension header,
> rather than defining only one 'header' type for that kind of header, you
> can define one for routing headers with 1 IPv6 address, one for routing
> headers with 2 IPv6 addresses, one for 3, etc. as many as you plan to
> support in your program.  Then have a separate action in a table for adding
> exactly one of those types of headers, with more action parameter data for
> the actions that add the larger headers vs. the smaller ones.
>
> Andy
>
>
> On Thu, Sep 20, 2018 at 6:52 PM <cristina.dominicini at aluno.ufes.br> wrote:
>
>> Hi Vladimir
>>
>>
>> Thank you very much for the quick answer.
>>
>> This was exactly the solution I tried to implement, using a source
>> routing header and a header stack:
>>
>> ==========
>>
>> header srcRoute_t {
>>     bit<1>    bos;
>>     bit<15>   port;
>> }
>>
>> header dummySrcRoute_t {
>>     bit<1>    bos;
>>     bit<15>   port;
>> }
>>
>> struct headers {
>>     ethernet_t              ethernet;
>>     dummySrcRoute_t[MAX_HOPS]    dummySrcRoutes;
>>     srcRoute_t[MAX_HOPS]    srcRoutes;
>>     ipv4_t                  ipv4;
>> }
>>
>> ==========
>>
>>
>> But the source routing protocol is transparent to hosts. So, I need to
>> build the complete stack in the first switch (edge ingress switch).
>>
>> I understood that the way to add a header in P4 is by using a
>> match-action table in the ingress block, as I described in my last e-mail.
>> However, depending on the destination, I may have to add one, two or ten of
>> these srcRoute_t headers. So, how to build this table to cope with this
>> condition? The only solution that worked for me was to consider a fix
>> number of hops, and, then parse only the useful ones using this dummy
>> header to parse the ones I don't need, until I get to the beginning of the
>> IP header.
>>
>> Is there a better way to add these headers if the stack has variable size
>> (as in the example)?
>>
>> Thank you for the confirmation that P4 16 language does note support
>> encapsulation of variable-length headers.
>>
>>
>> Best Regards,
>>
>> Cristina
>>
>>
>> Em 20.09.2018 22:22, Vladimir Gurevich escreveu:
>>
>> Hello Cristina,
>>
>> First of all, I do not think that your specific use case requires
>> variable length headers. The standard practice is to use a stack of
>> fixed-length headers, each representing the information from one node.
>> Also, unless you really need to look up past those headers, the traditional
>> way of passing this information is by *prepending" the new info in front of
>> the existing stack.
>>
>> In other words, your examples should look like this:
>>
>>    - "switch 1 output port is 3, and switch 2 output port is 1" will be
>>    {1} {3}
>>    - "switch 1 output port is 3, switch 2 output port is 3, switch 3
>>    output port is 3, and switch 4 output port is 1" will be {1} {3} {3} {3}
>>
>> This allows each node to not even parse the stack of headers created by
>> the previous nodes. All you need to do is to add one header with your info
>> just after the header that precedes the stack.
>>
>> If you want a harder solution, you can parse the whole stack, but then
>> you will either have to have "end of stack" indicator (similar to BOS bit
>> in MPLS), or use a counter or do something else. The only advantage is that
>> this would allow you to parse the headers that follow this info, while
>> there will be several serious disadvantages: you will be limited to the
>> maximum number of headers defined at compile time and parsing will take
>> longer.
>>
>> So, my hope is that you will be able to solve the problem without using
>> variable-length headers to begin with.
>>
>> As for the original question, standard P4_16 (without any vendor-specific
>> externs) only allows one to extract, copy (assign) and deparse
>> variable-length headers. You can't create one "on the fly"
>>
>> Happy hacking,
>> Vladimir
>>
>> *Vladimir Gurevich*
>>
>> *Barefoot Networks*
>> *Director, Customer Training and Education*
>> Email: vag at barefootnetworks.com
>> Phone: (408) 833-4505
>>
>>
>> On Thu, Sep 20, 2018 at 5:48 PM <cristina.dominicini at aluno.ufes.br>
>> wrote:
>>
>>> Hi all,
>>>
>>> The parsing of variable-length headers is well documented in P4
>>> language. There are examples as the source routing tutorial (
>>> https://github.com/p4lang/tutorials/tree/master/exercises/source_routing)
>>> and the implementation of TCP options in the P4 16 manual.
>>>
>>> On the other hand, I could not find a way to add a variable-length
>>> header to a packet using P4 16 and v1model.
>>>
>>> My goal was to extend the source routing tutorial in order to answer a
>>> question of the "Food for thought" section: "How would you enhance your
>>> program to let the first switch add the path, so that source routing would
>>> be transparent to end-hosts?"
>>>
>>> Originally, this tutorial depends on a python script to generate the
>>> source routing headers, and the p4 program deals only with the source
>>> routing operation on headers that were already created by the hosts.
>>>
>>> Imagine two examples of output port list for source routing:
>>> {3 1} - which means switch 1 output port is 3, and switch 2 output port
>>> is 1
>>> {3 3 3 1} - which means switch 1 output port is 3, switch 2 output port
>>> is 3, switch 3 output port is 3, and switch 4 output port is 1
>>>
>>> So, depending on the path length, the size of the source routing list
>>> changes, and, consequently, the total header length changes.
>>>
>>> My start point was this very good documentation from Andy Fingerhut:
>>> https://github.com/jafingerhut/p4-guide/tree/master/rewrite-examples
>>>
>>> So, if no source routing header was found in the parsing stage, I can
>>> add it in the ingress block by consulting a table, where the match
>>> condition is the IP destination address, and the action is the content of
>>> my source routing header for reaching that destination. However, to do this
>>> I need to store the contents from the table in fixed size variables.
>>>
>>> I was only able to solve this problem if I consider a fixed-length
>>> source routing header when reading the action column from the table. Then,
>>> in the parsing stage, besides the useful source routing content, I also
>>> parse a dummy source routing content for the remaining bits in the header.
>>> In addition, I have to keep this dummy header during the routing process.
>>> The routing works, but clearly it is not an optimal implementation, since I
>>> have a header overhead that was not happening when the headers were created
>>> by the python script in the hosts.
>>>
>>> Does someone have a better idea on how to solve this type of problem
>>> (encapsulation of variable-length headers)? Does the P4 16 language support
>>> encapsulation of variable-length headers? Does the PSA architecture
>>> (instead of v1model) offer more flexibility to solve this type of problem?
>>>
>>> Thank you,
>>> Cristina
>>>
>>>
>>> _______________________________________________
>>> P4-dev mailing list
>>> P4-dev at lists.p4.org
>>> http://lists.p4.org/mailman/listinfo/p4-dev_lists.p4.org
>>
>> _______________________________________________
>> 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/20180922/ef6b8ffe/attachment-0001.html>


More information about the P4-dev mailing list