When implementing a network interface in RTL, you need a precise byte-offset map for every field in the frame. This post provides that reference for the most common combination: Ethernet II + IPv4 + UDP.

Layer Stack

[ Preamble (7B) + SFD (1B) ]  ← handled by PHY/MAC, not in user datapath
[ Ethernet II header        ]
  [ IPv4 header             ]
    [ UDP header            ]
      [ Application data    ]
[ FCS / CRC-32 (4B)         ]  ← often stripped/added by MAC IP
                                   (configurable option in Xilinx TEMAC / Tri-MAC)

Note: The preamble, SFD, and inter-packet gap (IPG) are inserted and stripped by the PHY/MAC layer and are typically not visible in the AXI-Stream user interface of a MAC IP core.


Ethernet II Header (14 bytes)

Offsets are relative to the start of the Ethernet frame (byte 0 = first byte of the Destination MAC).

OffsetSizeFieldNotes
0–56 BDestination MACBroadcast = FF:FF:FF:FF:FF:FF
6–116 BSource MACSender’s MAC address
12–132 BEtherType0x0800 = IPv4, 0x86DD = IPv6, 0x0806 = ARP
14–…variablePayloadIPv4 packet starts here
last 4 B4 BFCS (CRC-32)Covers DA through end of payload

IPv4 Header (minimum 20 bytes)

Offsets within the IPv4 packet (i.e., from Ethernet byte offset 14).

OffsetSizeFieldNotes
01 BVersion / IHLUpper nibble = 4 (IPv4); lower nibble = header length in 32-bit words (usually 5 → 20 B)
11 BDSCP / ECN(formerly ToS)
2–32 BTotal LengthIPv4 header + payload in bytes
4–52 BIdentificationFragment ID
6–72 BFlags + Fragment OffsetUpper 3 bits = flags (DF, MF); lower 13 bits = fragment offset
81 BTTLDecremented at each hop; drop when 0
91 BProtocol0x11 (17) = UDP, 0x06 (6) = TCP, 0x01 = ICMP
10–112 BHeader ChecksumOne’s complement of the IPv4 header only
12–154 BSource IPe.g., 192.168.1.10
16–194 BDestination IP
20–590–40 BOptionsPresent only when IHL > 5

UDP Header (8 bytes)

Offsets within the UDP segment (i.e., from Ethernet byte offset 34, assuming a 20-byte IPv4 header).

OffsetSizeFieldNotes
0–12 BSource PortEphemeral or well-known
2–32 BDestination Porte.g., 0x0035 (53) = DNS
4–52 BLengthUDP header + data in bytes (minimum 8)
6–72 BChecksumOptional in IPv4; covers pseudo-header + UDP header + data
8–(8+N−1)N BDataN = UDP Length − 8

Absolute Byte Offsets (No IPv4 Options)

For the common case of a 20-byte IPv4 header and no VLAN tag:

FieldEthernet-frame Offset
Destination MAC0–5
Source MAC6–11
EtherType12–13
IPv4 Version/IHL14
IPv4 Total Length16–17
IPv4 Protocol23
IPv4 Source IP26–29
IPv4 Destination IP30–33
UDP Source Port34–35
UDP Destination Port36–37
UDP Length38–39
UDP Checksum40–41
UDP Payload starts42

RTL Implementation Tips

Byte extraction in SystemVerilog (AXI-Stream, 8-bit byte lanes):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// Assuming rx_data[7:0] is valid, rx_byte_cnt tracks the current byte offset
logic [47:0] dst_mac;
logic [15:0] ethertype;
logic [7:0]  ip_protocol;
logic [15:0] udp_dst_port;

always_ff @(posedge clk) begin
    if (rx_valid && rx_ready) begin
        case (rx_byte_cnt)
            0:  dst_mac[47:40] <= rx_data;
            1:  dst_mac[39:32] <= rx_data;
            2:  dst_mac[31:24] <= rx_data;
            3:  dst_mac[23:16] <= rx_data;
            4:  dst_mac[15:8]  <= rx_data;
            5:  dst_mac[7:0]   <= rx_data;
            23: ip_protocol    <= rx_data;
            36: udp_dst_port[15:8] <= rx_data;
            37: udp_dst_port[7:0]  <= rx_data;
        endcase
    end
end

FCS handling: Most vendor MAC IP cores (Xilinx TEMAC, Tri-mode MAC) have an option to automatically append/verify FCS. When enabled, byte offsets above are correct. When disabled, subtract 4 bytes from the end of the frame to exclude FCS from payload processing.