> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/microsoft/eBPF-Event-Interceptor/llms.txt
> Use this file to discover all available pages before exploring further.

# UDP Event API Data Structures

> Structure definitions for UDP event data

## Structure Overview

The UDP Event API uses two main structures:

* **`event_t`** - Internal structure used by the eBPF kernel code
* **`udp_event_t`** - Consumer-facing structure returned by `DequeuePerfEvent()`

Both structures are packed (`#pragma pack(push, 1)`) to ensure consistent memory layout across compilation units.

***

## udp\_event\_t

The consumer-facing structure containing UDP event information. This is the structure returned by `DequeuePerfEvent()`.

### Definition

```c theme={null}
#pragma pack(push, 1)
struct udp_event_t {
    uint16_t family;
    uint32_t pid;
    uint32_t UserId;
    uint64_t EventTime;
    uint16_t SPT;
    uint16_t DPT;
    char task[16];
    uint64_t rx_b;
    uint64_t tx_b;
    uint32_t rxPkts;
    uint32_t txPkts;
    char SADDR[64];
    char DADDR[64];
};
#pragma pack(pop)
```

### Fields

<ResponseField name="family" type="uint16_t">
  Address family of the connection:

  * `AF_INET` (2) - IPv4
  * `AF_INET6` (10) - IPv6
</ResponseField>

<ResponseField name="pid" type="uint32_t">
  Process ID of the application that created the UDP socket.
</ResponseField>

<ResponseField name="UserId" type="uint32_t">
  User ID (UID) of the process owner. Useful for multi-user systems to track which user initiated the connection.
</ResponseField>

<ResponseField name="EventTime" type="uint64_t">
  Event timestamp in nanoseconds since Unix epoch (January 1, 1970).

  **Note**: This is adjusted from kernel time (since boot) to absolute system time using the boot time offset.
</ResponseField>

<ResponseField name="SPT" type="uint16_t">
  Source Port - The local UDP port number in host byte order.
</ResponseField>

<ResponseField name="DPT" type="uint16_t">
  Destination Port - The remote UDP port number in host byte order.
</ResponseField>

<ResponseField name="task" type="char[16]">
  Process name (command) that created the UDP socket. Limited to 16 characters including null terminator.

  Example values: `"curl"`, `"nc"`, `"python3"`, `"custom_app"`
</ResponseField>

<ResponseField name="rx_b" type="uint64_t">
  **Received Bytes** - Total number of bytes received on this UDP socket.

  Incremented in `udp_recvmsg` and `udpv6_recvmsg` kretprobes based on the return value of the kernel function.
</ResponseField>

<ResponseField name="tx_b" type="uint64_t">
  **Transmitted Bytes** - Total number of bytes transmitted on this UDP socket.

  Incremented in `udp_sendmsg` and `udpv6_sendmsg` kprobes based on the message length parameter.
</ResponseField>

<ResponseField name="rxPkts" type="uint32_t">
  **Received Packets** - Count of UDP packets received.

  **UDP-specific field**: This field is unique to the UDP API and not present in the TCP Event API. Incremented for each successful `recvmsg` call.
</ResponseField>

<ResponseField name="txPkts" type="uint32_t">
  **Transmitted Packets** - Count of UDP packets transmitted.

  **UDP-specific field**: This field is unique to the UDP API and not present in the TCP Event API. Incremented for each `sendmsg` call.
</ResponseField>

<ResponseField name="SADDR" type="char[64]">
  **Source Address** - String representation of the local IP address.

  * IPv4 format: `"192.168.1.100"`
  * IPv6 format: `"2001:db8::1"`

  Converted from binary format using `inet_ntop()`.
</ResponseField>

<ResponseField name="DADDR" type="char[64]">
  **Destination Address** - String representation of the remote IP address.

  * IPv4 format: `"8.8.8.8"`
  * IPv6 format: `"2001:4860:4860::8888"`

  Converted from binary format using `inet_ntop()`.
</ResponseField>

### Size

Total structure size: **168 bytes** (packed)

### Example: Reading IPv4 Event

```c theme={null}
#include <stdio.h>
#include <arpa/inet.h>
#include "common.h"

extern struct udp_event_t DequeuePerfEvent();

void process_ipv4_event() {
    struct udp_event_t event = DequeuePerfEvent();
    
    if (event.family == AF_INET) {
        printf("=== IPv4 UDP Event ===\n");
        printf("Process: %s (PID: %u, UID: %u)\n", 
               event.task, event.pid, event.UserId);
        printf("Time: %lu ns\n", event.EventTime);
        printf("Connection: %s:%u -> %s:%u\n",
               event.SADDR, event.SPT, event.DADDR, event.DPT);
        printf("Traffic: TX %llu bytes (%u pkts), RX %llu bytes (%u pkts)\n",
               event.tx_b, event.txPkts, event.rx_b, event.rxPkts);
    }
}
```

### Example: Reading IPv6 Event

```c theme={null}
#include <stdio.h>
#include <arpa/inet.h>
#include "common.h"

extern struct udp_event_t DequeuePerfEvent();

void process_ipv6_event() {
    struct udp_event_t event = DequeuePerfEvent();
    
    if (event.family == AF_INET6) {
        printf("=== IPv6 UDP Event ===\n");
        printf("Process: %s (PID: %u, UID: %u)\n", 
               event.task, event.pid, event.UserId);
        printf("Time: %lu ns\n", event.EventTime);
        printf("Connection: [%s]:%u -> [%s]:%u\n",
               event.SADDR, event.SPT, event.DADDR, event.DPT);
        printf("Traffic: TX %llu bytes (%u pkts), RX %llu bytes (%u pkts)\n",
               event.tx_b, event.txPkts, event.rx_b, event.rxPkts);
    }
}
```

### Example: Converting Timestamp

```c theme={null}
#include <time.h>
#include <stdio.h>
#include "common.h"

void print_event_time(struct udp_event_t *event) {
    // Convert nanoseconds to seconds
    time_t seconds = event->EventTime / 1000000000ULL;
    long nanoseconds = event->EventTime % 1000000000ULL;
    
    struct tm *tm_info = localtime(&seconds);
    char buffer[64];
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tm_info);
    
    printf("Event time: %s.%09ld\n", buffer, nanoseconds);
}
```

### Source Reference

`udpEvent/common.h:3-20`

***

## event\_t

Internal structure used by the eBPF kernel code to store event information. This structure is **not directly exposed** to API consumers.

### Definition

```c theme={null}
#pragma pack(push, 1)
struct event_t {
    uint16_t family;
    uint32_t pid;
    uint32_t UserId;
    uint64_t EventTime;
    uint16_t SPT;
    uint16_t DPT;
    char task[16];
    unsigned __int128 saddr;
    unsigned __int128 daddr;
    uint64_t rx_b;
    uint64_t tx_b;
    uint32_t rxPkts;
    uint32_t txPkts;
    uintptr_t sockPtr;
};
#pragma pack(pop)
```

### Fields

<ResponseField name="family" type="uint16_t">
  Address family (AF\_INET or AF\_INET6).
</ResponseField>

<ResponseField name="pid" type="uint32_t">
  Process ID.
</ResponseField>

<ResponseField name="UserId" type="uint32_t">
  User ID.
</ResponseField>

<ResponseField name="EventTime" type="uint64_t">
  Kernel timestamp in nanoseconds (time since boot).
</ResponseField>

<ResponseField name="SPT" type="uint16_t">
  Source port.
</ResponseField>

<ResponseField name="DPT" type="uint16_t">
  Destination port.
</ResponseField>

<ResponseField name="task" type="char[16]">
  Process name.
</ResponseField>

<ResponseField name="saddr" type="unsigned __int128">
  **Source address in binary format** - 128-bit value supporting both IPv4 and IPv6:

  * IPv4: Stored in lower 32 bits
  * IPv6: Full 128-bit address

  This is converted to string format (SADDR) in `udp_event_t`.
</ResponseField>

<ResponseField name="daddr" type="unsigned __int128">
  **Destination address in binary format** - 128-bit value supporting both IPv4 and IPv6:

  * IPv4: Stored in lower 32 bits
  * IPv6: Full 128-bit address

  This is converted to string format (DADDR) in `udp_event_t`.
</ResponseField>

<ResponseField name="rx_b" type="uint64_t">
  Received bytes counter.
</ResponseField>

<ResponseField name="tx_b" type="uint64_t">
  Transmitted bytes counter.
</ResponseField>

<ResponseField name="rxPkts" type="uint32_t">
  Received packets counter.
</ResponseField>

<ResponseField name="txPkts" type="uint32_t">
  Transmitted packets counter.
</ResponseField>

<ResponseField name="sockPtr" type="uintptr_t">
  **Socket pointer** - Kernel address of the `struct sock` object.

  Used internally as a hash key to track and aggregate statistics for the same socket across multiple kernel events.

  **Not exposed** in the consumer-facing `udp_event_t` structure.
</ResponseField>

### Key Differences from udp\_event\_t

| Field           | event\_t            | udp\_event\_t    | Notes                          |
| --------------- | ------------------- | ---------------- | ------------------------------ |
| Address storage | `unsigned __int128` | `char[64]`       | Binary vs. string format       |
| Socket tracking | `sockPtr` field     | Not present      | Internal use only              |
| Address fields  | `saddr`, `daddr`    | `SADDR`, `DADDR` | Lowercase vs. uppercase naming |

### Purpose

This structure is used for:

1. **Perf buffer communication** - Events are submitted from kernel to userspace via BPF perf buffer
2. **Hash table storage** - Events are stored in `otherHash` BPF map using `sockPtr` as key
3. **Event aggregation** - Multiple kernel events for the same socket are aggregated by updating the same `event_t` entry

### Conversion to udp\_event\_t

The `DequeuePerfEvent()` function converts `event_t` to `udp_event_t`:

```c theme={null}
// Address conversion (IPv4 example)
inet_ntop(AF_INET, (struct in_addr *)&(event->saddr), toConsumer.SADDR, 128);
inet_ntop(AF_INET, (struct in_addr *)&(event->daddr), toConsumer.DADDR, 128);

// Address conversion (IPv6 example)
inet_ntop(AF_INET6, (struct in_addr6 *)&(event->saddr), toConsumer.SADDR, 128);
inet_ntop(AF_INET6, (struct in_addr6 *)&(event->daddr), toConsumer.DADDR, 128);
```

### Source Reference

`udpEvent/common.h:24-41`

***

## Differences from TCP Structures

### Additional Fields in UDP

The UDP event structures include packet count fields that are **not present** in the TCP Event API:

<Expandable title="UDP-specific fields">
  <ResponseField name="rxPkts" type="uint32_t">
    Number of received UDP packets. TCP does not track individual packets as it's stream-oriented.
  </ResponseField>

  <ResponseField name="txPkts" type="uint32_t">
    Number of transmitted UDP packets. TCP does not track individual packets as it's stream-oriented.
  </ResponseField>
</Expandable>

### Rationale

UDP is a **packet-oriented** protocol where each `sendmsg` or `recvmsg` call corresponds to a discrete datagram. Packet counts are meaningful metrics for:

* Analyzing packet loss patterns
* Calculating average packet sizes
* Monitoring packet rate (packets per second)
* Detecting fragmentation issues

TCP, being **stream-oriented**, does not expose packet-level semantics to applications, making packet counts less relevant.

### Structure Comparison

| Field       | TCP event\_t | UDP event\_t | UDP udp\_event\_t |
| ----------- | ------------ | ------------ | ----------------- |
| family      | ✓            | ✓            | ✓                 |
| pid         | ✓            | ✓            | ✓                 |
| UserId      | ✓            | ✓            | ✓                 |
| EventTime   | ✓            | ✓            | ✓                 |
| SPT         | ✓            | ✓            | ✓                 |
| DPT         | ✓            | ✓            | ✓                 |
| task        | ✓            | ✓            | ✓                 |
| saddr/SADDR | ✓            | ✓            | ✓                 |
| daddr/DADDR | ✓            | ✓            | ✓                 |
| rx\_b       | ✓            | ✓            | ✓                 |
| tx\_b       | ✓            | ✓            | ✓                 |
| **rxPkts**  | ✗            | **✓**        | **✓**             |
| **txPkts**  | ✗            | **✓**        | **✓**             |
| sockPtr     | ✓            | ✓            | ✗                 |
