Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

XDP declarations are moved from ebpf_nethooks.h. #3793

Merged
merged 18 commits into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/debugging.md
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ to illustrate some basic steps. So now let's move on to the real program in the

> netsh ebpf show disassembly droppacket_unsafe.o xdp_test
; C:\your\path\ebpf-for-windows\tests\sample/unsafe/droppacket_unsafe.c:22
; DropPacket(xdp_md_t* ctx)
; DropPacket(xdp_test_md_t* ctx)
0: r0 = 1
; C:\your\path\ebpf-for-windows\tests\sample/unsafe/droppacket_unsafe.c:24
; IPV4_HEADER* ip_header = (IPV4_HEADER*)ctx->data;
Expand Down
14 changes: 7 additions & 7 deletions docs/eBpfExtensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,23 +167,23 @@ invoking an eBPF program. The various fields of this struct are as follows.

For example, for the XDP_TEST program types, the context data structure is as follows:
```c
// XDP_TEST hook. We use "struct xdp_md" for cross-platform compatibility.
typedef struct xdp_md
// XDP_TEST hook. We use "struct xdp_test_md" for cross-platform compatibility.
typedef struct xdp_test_md
{
void* data; ///< Pointer to start of packet data.
void* data_end; ///< Pointer to end of packet data.
uint64_t data_meta; ///< Packet metadata.

/* size: 12, cachelines: 1, members: 3 */
/* last cacheline: 12 bytes */
} xdp_md_t;
} xdp_test_md_t;
```
The corresponding context descriptor looks like:
```c
const ebpf_context_descriptor_t g_xdp_context_descriptor = {sizeof(xdp_md_t),
EBPF_OFFSET_OF(xdp_md_t, data),
EBPF_OFFSET_OF(xdp_md_t, data_end),
EBPF_OFFSET_OF(xdp_md_t, data_meta)};
const ebpf_context_descriptor_t g_xdp_context_descriptor = {sizeof(xdp_test_md_t),
EBPF_OFFSET_OF(xdp_test_md_t, data),
EBPF_OFFSET_OF(xdp_test_md_t, data_end),
EBPF_OFFSET_OF(xdp_test_md_t, data_meta)};
```
If any of the data or metadata pointer fields are not present on the context structure, the offset value is set to -1
in the context descriptor.
Expand Down
21 changes: 11 additions & 10 deletions docs/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -491,38 +491,39 @@ structure which contains an arbitrary amount of data. (Tail calls to
programs can have more than one argument, but hooks put all the info in a
hook-specific context structure passed as one argument.)

The "xdp_test" hook point has the following prototype in `ebpf_nethooks.h`:
The "xdp_test" hook point has the following prototype in `ebpf_xdp_test_hooks.h`:

```c
typedef struct xdp_md
typedef struct xdp_test_md
{
void* data; // Pointer to start of packet data.
void* data_end; // Pointer to end of packet data.
uint64_t data_meta; // Packet metadata.
uint32_t ingress_ifindex; // Ingress interface index.
} xdp_md_t;
} xdp_test_md_t;

typedef enum _xdp_action
typedef enum _xdp_action_test
{
XDP_PASS = 1, // Allow the packet to pass.
XDP_DROP, // Drop the packet.
XDP_TX // Bounce the received packet back out the same NIC it arrived on.
} xdp_action_t;
} xdp_action_test_t;
shpalani marked this conversation as resolved.
Show resolved Hide resolved

typedef xdp_action_t xdp_hook_t(xdp_md_t* context);
typedef xdp_action_test_t xdp_hook_t(xdp_test_md_t* context);
```

A sample eBPF program might look like this:

```c
#include "bpf_helpers.h"
#include "ebpf_nethooks.h"
#include "ebpf_xdp_test_hooks.h"

// Put "xdp_test" in the section name to specify XDP_TEST as the hook.
// The SEC macro below has the same effect as the
// clang pragma used in section 2 of this tutorial.
SEC("xdp_test")
int my_xdp_parser(xdp_md_t* ctx)
int my_xdp_parser(xdp_test_md_t* ctx)
{
int length = (char *)ctx->data_end - (char *)ctx->data;

Expand Down Expand Up @@ -597,15 +598,15 @@ verifier is the same as above but XDP_TEST instead had a different struct
definition:

```c
typedef struct _xdp_md_t
typedef struct _xdp_test_md_t
{
uint64_t more;
uint64_t stuff;
uint64_t here;
void* data;
void* data_end;
uint64_t data_meta;
} xdp_md_t;
} xdp_test_md_t;
```

Now our sample program that checks the length would now be looking for
Expand All @@ -628,7 +629,7 @@ by r1 (since the first argument is in register R1) past the end of the
valid buffer of size 32. This illustrates why ideally the same header
file (ebpf_nethooks.h in the above example) should be used by the eBPF program,
the component exposing the hook, and the verifier itself, e.g., so that
the size of the context struct could be `sizeof(xdp_md_t)`
the size of the context struct could be `sizeof(xdp_test_md_t)`
rather than hardcoding the number 32 in the above example.

## 4.2. Helper functions and arguments
Expand Down
1 change: 1 addition & 0 deletions include/bpf_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@

#define bpf_map_def _ebpf_map_definition_in_file
#include "ebpf_nethooks.h"
#include "ebpf_xdp_test_hooks.h"
shpalani marked this conversation as resolved.
Show resolved Hide resolved

#endif

Expand Down
54 changes: 0 additions & 54 deletions include/ebpf_nethooks.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,64 +6,10 @@
// This file contains APIs for hooks and helpers that are
// exposed by netebpfext.sys for use by eBPF programs.

// XDP_TEST hook. We use "struct xdp_md" for cross-platform compatibility.
typedef struct xdp_md_
{
void* data; ///< Pointer to start of packet data.
void* data_end; ///< Pointer to end of packet data.
uint64_t data_meta; ///< Packet metadata.
uint32_t ingress_ifindex; ///< Ingress interface index.

/* size: 26, cachelines: 1, members: 4 */
/* last cacheline: 26 bytes */
} xdp_md_t;

typedef enum _xdp_action
{
XDP_PASS = 1, ///< Allow the packet to pass.
XDP_DROP, ///< Drop the packet.
XDP_TX ///< Bounce the received packet back out the same NIC it arrived on.
} xdp_action_t;

/**
* @brief Handle an incoming packet as early as possible.
*
* Program type: \ref EBPF_PROGRAM_TYPE_XDP_TEST
*
* @param[in] context Packet metadata.
* @retval XDP_PASS Allow the packet to pass.
* @retval XDP_DROP Drop the packet.
* @retval XDP_TX Bounce the received packet back out the same NIC it arrived on.
*/
typedef xdp_action_t
xdp_hook_t(xdp_md_t* context);

// XDP_TEST helper functions.
#define XDP_EXT_HELPER_FN_BASE 0xFFFF

#ifndef __doxygen
#define EBPF_HELPER(return_type, name, args) typedef return_type(*const name##_t) args
#endif

typedef enum
{
BPF_FUNC_xdp_adjust_head = XDP_EXT_HELPER_FN_BASE + 1,
} ebpf_nethook_helper_id_t;

/**
* @brief Adjust XDP_TEST context data pointer.
*
* @param[in] ctx XDP_TEST context.
* @param[in] delta Number of bytes to move the data pointer by.
*
* @retval 0 The operation was successful.
* @retval <0 A failure occurred.
*/
EBPF_HELPER(int, bpf_xdp_adjust_head, (xdp_md_t * ctx, int delta));
#ifndef __doxygen
#define bpf_xdp_adjust_head ((bpf_xdp_adjust_head_t)BPF_FUNC_xdp_adjust_head)
#endif

// BIND hook

typedef enum _bind_operation
Expand Down
65 changes: 65 additions & 0 deletions include/ebpf_xdp_test_hooks.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright (c) eBPF for Windows contributors
shpalani marked this conversation as resolved.
Show resolved Hide resolved
// SPDX-License-Identifier: MIT
#pragma once
#include <stdint.h>

// This file contains APIs for hooks and helpers that are
// exposed by netebpfext.sys for use by eBPF xdp test programs.

// XDP_TEST hook.
typedef struct xdp_test_md_
shpalani marked this conversation as resolved.
Show resolved Hide resolved
{
void* data; ///< Pointer to start of packet data.
void* data_end; ///< Pointer to end of packet data.
uint64_t data_meta; ///< Packet metadata.
uint32_t ingress_ifindex; ///< Ingress interface index.

/* size: 26, cachelines: 1, members: 4 */
/* last cacheline: 26 bytes */
} xdp_test_md_t;

typedef enum _xdp_action_test
shpalani marked this conversation as resolved.
Show resolved Hide resolved
{
XDP_PASS = 1, ///< Allow the packet to pass.
XDP_DROP, ///< Drop the packet.
XDP_TX ///< Bounce the received packet back out the same NIC it arrived on.
} xdp_action_test_t;
shpalani marked this conversation as resolved.
Show resolved Hide resolved

/**
* @brief Handle an incoming packet as early as possible.
*
* Program type: \ref EBPF_PROGRAM_TYPE_XDP_TEST
*
* @param[in] context Packet metadata.
* @retval XDP_PASS Allow the packet to pass.
* @retval XDP_DROP Drop the packet.
* @retval XDP_TX Bounce the received packet back out the same NIC it arrived on.
*/
typedef xdp_action_test_t
xdp_hook_t(xdp_test_md_t* context);

// XDP_TEST helper functions.
#define XDP_EXT_HELPER_FN_BASE 0xFFFF

#ifndef __doxygen
#define EBPF_HELPER(return_type, name, args) typedef return_type(*const name##_t) args
#endif

typedef enum
{
BPF_FUNC_xdp_adjust_head = XDP_EXT_HELPER_FN_BASE + 1,
} ebpf_nethook_helper_id_t;

/**
* @brief Adjust XDP_TEST context data pointer.
*
* @param[in] ctx XDP_TEST context.
* @param[in] delta Number of bytes to move the data pointer by.
*
* @retval 0 The operation was successful.
* @retval <0 A failure occurred.
*/
EBPF_HELPER(int, bpf_xdp_adjust_head, (xdp_test_md_t * ctx, int delta));
#ifndef __doxygen
#define bpf_xdp_adjust_head ((bpf_xdp_adjust_head_t)BPF_FUNC_xdp_adjust_head)
#endif
9 changes: 5 additions & 4 deletions netebpfext/net_ebpf_ext_program_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "ebpf_nethooks.h"
#include "ebpf_program_types.h"
#include "ebpf_shared_framework.h"
#include "ebpf_xdp_test_hooks.h"

#define XDP_EXT_HELPER_FUNCTION_START EBPF_MAX_GENERAL_HELPER_FUNCTION

Expand All @@ -28,10 +29,10 @@ static const ebpf_helper_function_prototype_t _xdp_test_ebpf_extension_helper_fu

// XDP_TEST program information.
static const ebpf_context_descriptor_t _ebpf_xdp_test_context_descriptor = {
sizeof(xdp_md_t),
EBPF_OFFSET_OF(xdp_md_t, data),
EBPF_OFFSET_OF(xdp_md_t, data_end),
EBPF_OFFSET_OF(xdp_md_t, data_meta)};
sizeof(xdp_test_md_t),
EBPF_OFFSET_OF(xdp_test_md_t, data),
EBPF_OFFSET_OF(xdp_test_md_t, data_end),
EBPF_OFFSET_OF(xdp_test_md_t, data_meta)};

static const ebpf_program_type_descriptor_t _ebpf_xdp_test_program_type_descriptor = {
EBPF_PROGRAM_TYPE_DESCRIPTOR_HEADER,
Expand Down
18 changes: 9 additions & 9 deletions netebpfext/net_ebpf_ext_xdp.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ typedef struct _net_ebpf_extension_xdp_wfp_filter_context
// XDP Program Information NPI Provider.
shpalani marked this conversation as resolved.
Show resolved Hide resolved
//
static int
_net_ebpf_xdp_adjust_head(_Inout_ xdp_md_t* ctx, int delta);
_net_ebpf_xdp_adjust_head(_Inout_ xdp_test_md_t* ctx, int delta);

static ebpf_result_t
_ebpf_xdp_context_create(
Expand Down Expand Up @@ -307,7 +307,7 @@ net_ebpf_ext_xdp_unregister_providers()
*/
typedef struct _net_ebpf_xdp_md
{
xdp_md_t base;
xdp_test_md_t base;
NET_BUFFER_LIST* original_nbl;
NET_BUFFER_LIST* cloned_nbl;
} net_ebpf_xdp_md_t;
Expand Down Expand Up @@ -437,7 +437,7 @@ _net_ebpf_ext_free_nbl(_Inout_ NET_BUFFER_LIST* nbl, BOOLEAN free_data)
//

static int
_net_ebpf_xdp_adjust_head(_Inout_ xdp_md_t* ctx, int delta)
_net_ebpf_xdp_adjust_head(_Inout_ xdp_test_md_t* ctx, int delta)
{
int return_value = 0;
NDIS_STATUS ndis_status = NDIS_STATUS_SUCCESS;
Expand Down Expand Up @@ -777,7 +777,7 @@ net_ebpf_ext_layer_2_classify(
}

/**
* @brief Build a xdp_md_t context for the eBPF program. This includes copying the packet data and
* @brief Build a xdp_test_md_t context for the eBPF program. This includes copying the packet data and
* metadata into a contiguous buffer and building an MDL chain for the same.
*
* @param[in] data_in The packet data.
Expand Down Expand Up @@ -849,8 +849,8 @@ _ebpf_xdp_context_create(
new_context->base.data = (void*)data_in;
new_context->base.data_end = (void*)(data_in + data_size_in);

if (context_in != NULL && context_size_in >= sizeof(xdp_md_t)) {
xdp_md_t* xdp_context = (xdp_md_t*)context_in;
if (context_in != NULL && context_size_in >= sizeof(xdp_test_md_t)) {
xdp_test_md_t* xdp_context = (xdp_test_md_t*)context_in;
new_context->base.data_meta = xdp_context->data_meta;
new_context->base.ingress_ifindex = xdp_context->ingress_ifindex;
}
Expand Down Expand Up @@ -907,11 +907,11 @@ _ebpf_xdp_context_delete(
// Copy some fields from the context to the output buffer.
if (context_out != NULL && context_size_out != NULL) {
size_t context_size = *context_size_out;
if (context_size > sizeof(xdp_md_t)) {
context_size = sizeof(xdp_md_t);
if (context_size > sizeof(xdp_test_md_t)) {
context_size = sizeof(xdp_test_md_t);
}

xdp_md_t* xdp_context_out = (xdp_md_t*)context_out;
xdp_test_md_t* xdp_context_out = (xdp_test_md_t*)context_out;
xdp_context_out->data_meta = xdp_context->base.data_meta;
xdp_context_out->ingress_ifindex = xdp_context->base.ingress_ifindex;
*context_size_out = context_size;
Expand Down
8 changes: 4 additions & 4 deletions tests/end_to_end/end_to_end.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ droppacket_test(ebpf_execution_type_t execution_type)
REQUIRE(bpf_map_update_elem(dropped_packet_map_fd, &key, &value, EBPF_ANY) == EBPF_SUCCESS);

// Test that we drop the packet and increment the map
xdp_md_t ctx0{packet0.data(), packet0.data() + packet0.size(), 0, TEST_IFINDEX};
xdp_test_md_t ctx0{packet0.data(), packet0.data() + packet0.size(), 0, TEST_IFINDEX};

uint32_t hook_result;
REQUIRE(hook.fire(&ctx0, &hook_result) == EBPF_SUCCESS);
Expand All @@ -454,7 +454,7 @@ droppacket_test(ebpf_execution_type_t execution_type)

// Create a normal (not 0-byte) UDP packet.
auto packet10 = prepare_udp_packet(10, ETHERNET_TYPE_IPV4);
xdp_md_t ctx10{packet10.data(), packet10.data() + packet10.size(), 0, TEST_IFINDEX};
xdp_test_md_t ctx10{packet10.data(), packet10.data() + packet10.size(), 0, TEST_IFINDEX};

// Test that we don't drop the normal packet.
REQUIRE(hook.fire(&ctx10, &hook_result) == EBPF_SUCCESS);
Expand Down Expand Up @@ -499,7 +499,7 @@ droppacket_test(ebpf_execution_type_t execution_type)
REQUIRE(bpf_map_delete_elem(dropped_packet_map_fd, &key) == EBPF_SUCCESS);

// Fire a 0-length packet on any interface that is not in the map, which should be allowed.
xdp_md_t ctx4{packet0.data(), packet0.data() + packet0.size(), 0, if_index + 1};
xdp_test_md_t ctx4{packet0.data(), packet0.data() + packet0.size(), 0, if_index + 1};
REQUIRE(hook.fire(&ctx4, &hook_result) == EBPF_SUCCESS);
REQUIRE(hook_result == XDP_PASS);
REQUIRE(bpf_map_lookup_elem(dropped_packet_map_fd, &key, &value) == EBPF_SUCCESS);
Expand Down Expand Up @@ -1770,7 +1770,7 @@ _xdp_reflect_packet_test(ebpf_execution_type_t execution_type, ADDRESS_FAMILY ad
udp_packet_t packet(address_family);
packet.set_destination_port(ntohs(REFLECTION_TEST_PORT));

xdp_md_t ctx{packet.data(), packet.data() + packet.size(), 0, TEST_IFINDEX};
xdp_test_md_t ctx{packet.data(), packet.data() + packet.size(), 0, TEST_IFINDEX};

uint32_t hook_result;
REQUIRE(hook.fire(&ctx, &hook_result) == EBPF_SUCCESS);
Expand Down
Loading
Loading