Endianness clarifications
Endianness of packet's header values, matches and actions:
The rofl-pipeline library is designed to work with packet header values in a specially aligned Network Byte Order (NBO).
The reason for that lays in improving the performance of accessing those values in the packet headers. The spirit is to minimize the operations necessary to access those values(e.g. avoid unnecessary shifts). For this reason all the packet header values remain in NBO. The values that do not fill a standard type (u8, u16, u32 and u64) are stored in the lower part of the memory and properly masked.
This alignment is kept internally in the library. The functions to initialize (constructors) entry matches and actions must provide the values in Host Byte Order(HBO) always. Special getter functions return the HBO representation for convenience (e.g. of1x_get_match_value16(), of1x_get_match_mask8() or of1x_get_packet_action_field64()) Nevertheless the interface for accessing the packet header values (rofl/datapath/pipeline/platform/packet.h), part of the Software Packet Processing (pp) APIs, uses this special alignment for the performance reasons already mentioned.
Following you may find a detailed explanation of them:
All the matches, actions and other values that do not external to packet (port_in, port_phy_in, metadata, queue and packet length) are kept in Host Byte Order(HBO).
For the rest of the values that are extracted (get) or modified (set) on packet headers, Network Byte Order is used. The non complete values have an special alignment explained here:
- mac address (6 bytes): Passed as an u64 variable where the 6 lower bytes are occupied with the mac address in NBO and the upper 2 are empty. Example:
mac_addr = 0x112233445566
-> in memory:uint_8* mac[8] = {0x11,0x22,0x33,0x44,0x55,0x66,0x00,0x00}
which is represented in a BE machine as and in a LE machine as
- vlan vid (12 bits): Passed as an u16 variable where the vid lays in the upper 12 bits in NBO and the 4 lower bits are empty. Example:
-> in memoryuint_8* vid[2] = {0x02,0x34}
which is represented in a BE machine as, and in a LE machine as
- vlan pcp (3 bits) Passed as an u8 variable where the pcp lays in the upper 3 bits and the 5 lower bits are empty. Example:
-> in memory
which is represented in as
- mpls label (20 bits): Passed as an u32 variable where the label lays in the lower 20 bits and the upper 12 are empty. Example:
-> in memory:uint_8* label[4] = {0x12,0x34,0x50,0x00}
which is represented in a BE machine as and in a LE machine as
- mpls tc (3 bits) Passed as an u8 variable where the tc lays in the 2nd to 4th bits and the other bits are empty. Example:
-> in memory
which is represented in as
- ip dscp (6 bytes) Passed as an u8 variable where the dscp lays in the upper 6 bits and the lower 2 bits are empty. Example:
-> in memory
which is represented in as
- ipv6 flow label (20 bits) Passed as an u32 variable where the flabel lays from the 4th to the 24th bits and the other 12 are empty. Example:
-> in memory:uint_8* flabel[4] = {0x01,0x23,0x45,0x00}
which is represented in a BE machine as and in a LE machine as
- pbb isid (3 bytes): Passed as an u32 variable where the isid lays in the lower 3 bytes and the upper byte is empty. Example:
-> in memory:uint_8* isid[4] = {0x12,0x34,0x56,0x00}
which is represented in a BE machine as and in a LE machine as