C Fundamentals

Struct, Memory Layout and Byte Order

Struct, memory layout, and byte order - critical topics for BPF verifier errors and network programming.

1.10 Struct, Union, Enum

Prerequisite: Complete Pointers and Strings first.

  • struct definition and access (. and ->)
  • Nested structs
  • union (same memory, different type)
  • enum (constant set)
  • typedef aliasing

Used everywhere in BPF: Packet headers, map definitions, context structs.

// BPF Map definition - struct syntax
struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __uint(max_entries, 1024);
    __type(key, u64);
    __type(value, u64);
} my_map SEC(".maps");

Related eBPFHub exercises:

  • “Maps and multiple programs” - BPF map struct syntax
  • “Introduction (kprobes)” - nested struct access with struct sock, struct sock_common
  • “DNS packet parsing” - struct dns_header definition

See in xdp-tutorial:

  • common/parsing_helpers.h - struct hdr_cursor, struct vlan_hdr
  • basic03-map-counter/xdp_prog_kern.c:11-16 - BPF map definition

Exercise: Write struct ethhdr by hand: h_dest[6], h_source[6], h_proto.


1.11 Memory Layout, Padding, and Alignment (BPF CRITICAL)

Prerequisite: Complete structs first.

This topic is very important for BPF verifier errors!

  • Struct padding (the compiler adds padding automatically)
  • sizeof vs actual data size
  • Removing padding with #pragma pack(n)
  • Using __attribute__((packed))
  • Explicit padding (adding a pad member)
  • Memory alignment rules

Why it is critical in BPF:

struct called_info {
    u64 start;  // 8-byte
    u64 end;    // 8-byte
    u32 sector; // 4-byte
}; // sizeof = 24 (not 20!)
// Verifier: "invalid indirect read from stack off -80+20 size 24"

Solution - add explicit padding:

struct called_info {
    u64 start;
    u64 end;
    u32 sector;
    u32 pad;    // explicit padding
}; // sizeof = 24, all bytes initialized

eBPFHub: In the “Cross-syscall state tracking” exercise, you will use a composite map key struct:

struct pid_fd_key {
    u64 pid;    // 8-byte aligned
    u32 fd;     // 4-byte -> caution: padding may occur
};

Exercise: Write structs with different types, check with sizeof, and observe the padding.


1.12 Byte Order (Endianness) - Essential for Network Programming

Prerequisite: Complete bitwise operations first.

  • Big-endian vs Little-endian
  • Network byte order (big-endian)
  • Host byte order (depends on the CPU)
  • Conversion functions: htons, ntohs, htonl, ntohl

In BPF:

  • bpf_ntohs() -> network to host (16-bit) - port numbers
  • bpf_htons() -> host to network (16-bit) - protocol comparison
  • bpf_ntohl() -> network to host (32-bit) - IP addresses
  • bpf_htonl() -> host to network (32-bit)
// Ethernet type field is in network byte order
if (eth->h_proto == bpf_htons(ETH_P_IP)) {
    // IPv4 packet
}

Related eBPFHub exercises:

  • “Tracking network connections” - port conversion with bpf_ntohs(addr.sin_port)
  • “DNS packet parsing” - IPv4 address conversion with bpf_ntohl(ip)

Reading: Computer Networking Fundamentals - networking fundamentals, including byte order.

Exercise:

  1. Split 0x1234 into bytes in both big-endian and little-endian
  2. Convert the IP address 192.168.1.1 to network byte order