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

extension_header #3326

Merged
merged 5 commits into from
Mar 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
49 changes: 39 additions & 10 deletions docs/eBpfExtensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,23 @@ initialized as follows:
* `NpiSpecificCharacteristics`: Pointer to structure of type `ebpf_extension_data_t`.
* The `data` field of this structure should point to a structure of type `ebpf_program_data_t`.

#### `ebpf_extension_header_t` Struct
This is a mandatory header that is common to all data structures needed by eBPF extensions to register with the eBPF framework.
* `version`: Version of the extension data structure.
* `size`: Size of the extension data structure.
When populating these data structures, the correct `version` and `size` fields must be set. The set of current version numbers and the
size for the various extension structures are listed in `ebpf_windows.h`. For example:
```c
#define EBPF_PROGRAM_TYPE_DESCRIPTOR_CURRENT_VERSION 1
#define EBPF_PROGRAM_TYPE_DESCRIPTOR_CURRENT_VERSION_SIZE \
(EBPF_OFFSET_OF(ebpf_program_type_descriptor_t, is_privileged) + sizeof(char))
```
> NOTE: Extension developers **must not** set the `size` field of these structures to `sizeof()` of the corresponding type. Instead,
> the `CURRENT_VERSION_SIZE` macros defined in `ebpf_windows.h` should be used.

#### `ebpf_program_data_t` Struct
The various fields of this structure should be set as follows:
* `header`: Version and size.
* `program_info`: Pointer to `ebpf_program_info_t`.
* `program_type_specific_helper_function_addresses`: Pointer to `ebpf_helper_function_addresses_t`. This structure
provides the helper functions that are exclusive to this program type.
Expand All @@ -77,12 +92,14 @@ context structure and populates the returned data and context buffers.

#### `ebpf_program_info_t` Struct
The various fields of this structure should be set as follows:
* `program_type_descriptor`: Field of type `ebpf_program_type_descriptor_t`.
* `header`: Version and size.
* `program_type_descriptor`: Pointer to `ebpf_program_type_descriptor_t`.
* `count_of_helpers`: The number of helper functions that are implemented by this extension for the given program type.
* `helper_prototype`: Pointer to array of `ebpf_helper_function_prototype_t`.

#### `ebpf_program_type_descriptor_t` Struct
The various fields of this structure should be set as follows:
* `header`: Version and size.
* `name`: Friendly name of the program type.
* `context_descriptor`: Pointer of type `ebpf_context_descriptor_t`.
* `program_type`: GUID for the program type. This should be the same as the `NpiId` in `NPI_REGISTRATION_INSTANCE` as
Expand All @@ -94,6 +111,7 @@ field should be set to `0 (BPF_PROG_TYPE_UNSPEC)`.
#### `ebpf_context_descriptor_t` Struct
This structure (as the name signifies) provides a description of the context parameter that a hook passes when
invoking an eBPF program. The various fields of this struct are as follows.
* `header`: Version and size.
* `size`: Size of the context structure.
* `data`: Offset (in bytes) to the field in the context structure that is pointing to the beginning of context data.
* `end`: Offset (in bytes) to the field in the context structure that is pointing to the end of context data.
Expand Down Expand Up @@ -124,6 +142,7 @@ in the context descriptor.

#### `ebpf_helper_function_prototype_t` Struct
This structure is used to describe the prototypes of the various helper functions implemented by the extension.
* `header`: Version and size.
* `helper_id`: Integer signifying the helper function ID. (See section 2.6).
Helper function IDs for different program types need not be unique.
* `name`: Helper function name.
Expand Down Expand Up @@ -189,7 +208,17 @@ This optional function is used to populate the flat buffers representing the dat
returned to the application when the `bpf_prog_test_run_opts` call completes. In addition, the function frees any
resources allocated in the `ebpf_program_context_create_t` call.

### 2.2 Program Information NPI Client Attach and Detach Callbacks
### 2.2 Backward compatibility of the Extension data structures
All the extension data structures are versioned. To maintain backward compatibility with the existing extensions, new fields **MUST** be added
to the end of a data structure. The constant defining the current size of the modified struct will be updated in `ebpf_windows.h`. Existing
eBPF extensions will continue to work without requiring recompilation. If an extension is modified to use a newly added field, the length
field must be updated accordingly.

If the change in data structure is such that it is no longer backward compatible (such as changing field type or position),
then the version number will be updated. In this case, the product version of eBPF for Windows must be updated to indicate a breaking change
as well. Existing eBPF extensions would need to be re-compiled to work with the latest version of eBPF.

### 2.3 Program Information NPI Client Attach and Detach Callbacks
The eBPF Execution Context registers a Program Information NPI client module with the NMR for every eBPF program that
gets loaded. The Execution Context will use the program type GUID of the program as the NPI ID of the client module.
And as a result, upon eBPF program load, the associated Program Information NPI client module will attach with the
Expand All @@ -198,7 +227,7 @@ client or provider dispatch tables. Neither does the client's `NpiSpecificCharac
special processing is required in the client attach and detach callback handler on the provider module. An extension
must not unload until there are no more attached Program Information NPI clients.

### 2.3 Hook NPI Provider Registration
### 2.4 Hook NPI Provider Registration
When registering itself to the NMR, the Hook NPI provider should have the
[`NPI_REGISTRATION_INSTANCE`](https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/netioddk/ns-netioddk-_npi_registration_instance)
initialized as follows:
Expand All @@ -220,7 +249,7 @@ requested attach type is supported by the Hook NPI provider. If not, the eBPF pr
The `bpf_attach_type` field should contain the equivalent bpf attach type integer. If there is no equivalent bpf
attach type, this field should be set to `0 (BPF_ATTACH_TYPE_UNSPEC)`.

### 2.4 Hook NPI Client Attach and Detach Callbacks
### 2.5 Hook NPI Client Attach and Detach Callbacks
The eBPF Execution Context registers a Hook NPI client module with the NMR for each program that is attached to a hook.
The attach type GUID is used as the NPI of the client module. And as a result, when an eBPF program gets attached to
a hook, the associated Hook NPI client module will attach to the corresponding Hook NPI provider module in the
Expand All @@ -246,7 +275,7 @@ Upon
[client detach callback](https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/netioddk/nc-netioddk-npi_provider_detach_client_fn)
the provider must free the per-client context passed in via `ProviderBindingContext` parameter.

### 2.5 Invoking an eBPF program from Hook NPI Provider
### 2.6 Invoking an eBPF program from Hook NPI Provider
To invoke an eBPF program, the extension uses the dispatch table supplied by the Hook NPI client during attaching.
The client dispatch table contains the functions, with the following type prototypes:

Expand Down Expand Up @@ -330,7 +359,7 @@ of time a batch is open and must not change IRQL between calling batch begin and
the number of times the program has been invoked, so callers should limit the number of calls within a batch to
prevent long delays in batch end.

### 2.6 Authoring Helper Functions
### 2.7 Authoring Helper Functions
An extension can provide an implementation of helper functions that can be invoked by the eBPF programs. The helper
functions can be of two types:
1. Program-Type specific: These helper functions can only be invoked by eBPF programs of a given program type. Usually,
Expand All @@ -356,7 +385,7 @@ The helper function ID for a general helper function must be in the range 0 - 65
The parameter and return types for these helper functions must adhere to the `ebpf_argument_type_t` and
`ebpf_return_type_t` enums.

### 2.7 Registering Program Types and Attach Types - eBPF Store
### 2.8 Registering Program Types and Attach Types - eBPF Store
The eBPF Execution Context loads an eBPF program from an ELF file that has program section(s) with section names. The
prefix to these names determines the program type. For example, the section name `"xdp_test"` implies that the corresponding
program type is `EBPF_PROGRAM_TYPE_XDP_TEST`.
Expand All @@ -373,15 +402,15 @@ To operate on the eBPF store, the user mode application needs to link with eBPFA
_In_reads_(section_info_count) const ebpf_program_section_info_t* section_info, uint32_t section_info_count);
```

- `ebpf_store_update_program_information`: updates program information in the eBPF store, given a pointer to an array of program information (i.e., `_ebpf_program_info`):
- `ebpf_store_update_program_information_array`: updates program information in the eBPF store, given a pointer to an array of program information (i.e., `_ebpf_program_info`):

```c
ebpf_result_t
ebpf_store_update_program_information(
ebpf_store_update_program_information_array(
_In_reads_(program_info_count) const ebpf_program_info_t* program_info, uint32_t program_info_count);
```

### 2.8 eBPF Sample Driver
### 2.9 eBPF Sample Driver
The eBPF for Windows project provides a
[sample extension driver](https://github.com/microsoft/ebpf-for-windows/tree/8f46b4020f79c32f994d3a59671ce8782e4b4cf0/tests/sample/ext)
as an example for how to implement an extension. This simple extension exposes a new program type, and implements a
Expand Down
2 changes: 1 addition & 1 deletion ebpfapi/Source.def
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ EXPORTS
ebpf_program_query_info
ebpf_store_delete_program_information
ebpf_store_delete_section_information
ebpf_store_update_program_information
ebpf_store_update_program_information_array
ebpf_store_update_section_information
libbpf_attach_type_by_name
libbpf_bpf_attach_type_str
Expand Down
11 changes: 3 additions & 8 deletions include/ebpf_extension.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,13 @@ typedef struct _ebpf_extension_program_dispatch_table

typedef struct _ebpf_extension_data
{
uint16_t version;
size_t size;
ebpf_extension_header_t header;
const void* data;
} ebpf_extension_data_t;

typedef struct _ebpf_attach_provider_data
{
ebpf_extension_header_t header;
ebpf_program_type_t supported_program_type;
bpf_attach_type_t bpf_attach_type;
enum bpf_link_type link_type;
Expand All @@ -118,9 +118,4 @@ typedef struct _ebpf_execution_context_state
const void* next_program;
uint32_t count;
} tail_call_state;
} ebpf_execution_context_state_t;

#define EBPF_ATTACH_CLIENT_DATA_VERSION 0
#define EBPF_ATTACH_PROVIDER_DATA_VERSION 1
#define EBPF_PROGRAM_INFORMATION_PROVIDER_DATA_VERSION 0
#define EBPF_MAX_GENERAL_HELPER_FUNCTION 0xFFFF
} ebpf_execution_context_state_t;
63 changes: 46 additions & 17 deletions include/ebpf_program_attach_type_guids.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,69 +21,98 @@ extern "C"
__declspec(selectany) ebpf_attach_type_t EBPF_ATTACH_TYPE_XDP = {
0x85e0d8ef, 0x579e, 0x4931, {0xb0, 0x72, 0x8e, 0xe2, 0x26, 0xbb, 0x2e, 0x9d}};

#define EBPF_ATTACH_TYPE_BIND_GUID \
{ \
0xb9707e04, 0x8127, 0x4c72, { 0x83, 0x3e, 0x05, 0xb1, 0xfb, 0x43, 0x94, 0x96 } \
}
/** @brief Attach type for handling socket bind() requests.
*
* Program type: \ref EBPF_PROGRAM_TYPE_BIND
*/
__declspec(selectany) ebpf_attach_type_t EBPF_ATTACH_TYPE_BIND = {
0xb9707e04, 0x8127, 0x4c72, {0x83, 0x3e, 0x05, 0xb1, 0xfb, 0x43, 0x94, 0x96}};
__declspec(selectany) ebpf_attach_type_t EBPF_ATTACH_TYPE_BIND = EBPF_ATTACH_TYPE_BIND_GUID;

#define EBPF_ATTACH_TYPE_CGROUP_INET4_CONNECT_GUID \
{ \
0xa82e37b1, 0xaee7, 0x11ec, { 0x9a, 0x30, 0x18, 0x60, 0x24, 0x89, 0xbe, 0xee } \
}
/** @brief The programs attached to the INET4_CONNECT hook will be invoked for
* connect() calls on TCP or UDP sockets or when a UDP socket sends a packet to
* a unique remote address/port tuple.
*
* Program type: \ref EBPF_PROGRAM_TYPE_CGROUP_SOCK_ADDR
*/
__declspec(selectany) ebpf_attach_type_t EBPF_ATTACH_TYPE_CGROUP_INET4_CONNECT = {
0xa82e37b1, 0xaee7, 0x11ec, {0x9a, 0x30, 0x18, 0x60, 0x24, 0x89, 0xbe, 0xee}};
__declspec(selectany)
ebpf_attach_type_t EBPF_ATTACH_TYPE_CGROUP_INET4_CONNECT = EBPF_ATTACH_TYPE_CGROUP_INET4_CONNECT_GUID;

#define EBPF_ATTACH_TYPE_CGROUP_INET6_CONNECT_GUID \
{ \
0xa82e37b2, 0xaee7, 0x11ec, { 0x9a, 0x30, 0x18, 0x60, 0x24, 0x89, 0xbe, 0xee } \
}
/** @brief The programs attached to the INET6_CONNECT hook will be invoked for
* connect() calls on TCP or UDP sockets or when a UDP socket sends a packet to
* a unique remote address/port tuple.
*
* Program type: \ref EBPF_PROGRAM_TYPE_CGROUP_SOCK_ADDR
*/
__declspec(selectany) ebpf_attach_type_t EBPF_ATTACH_TYPE_CGROUP_INET6_CONNECT = {
0xa82e37b2, 0xaee7, 0x11ec, {0x9a, 0x30, 0x18, 0x60, 0x24, 0x89, 0xbe, 0xee}};
__declspec(selectany)
ebpf_attach_type_t EBPF_ATTACH_TYPE_CGROUP_INET6_CONNECT = EBPF_ATTACH_TYPE_CGROUP_INET6_CONNECT_GUID;

#define EBPF_ATTACH_TYPE_CGROUP_INET4_RECV_ACCEPT_GUID \
{ \
0xa82e37b3, 0xaee7, 0x11ec, { 0x9a, 0x30, 0x18, 0x60, 0x24, 0x89, 0xbe, 0xee } \
}
/** @brief The programs attached to the INET4_RECV_ACCEPT hook will get invoked for
* TCP accept() calls or for the first unicast UDP packet from a unique remote
* address/port tuple.
*
* Program type: \ref EBPF_PROGRAM_TYPE_CGROUP_SOCK_ADDR
*/
__declspec(selectany) ebpf_attach_type_t EBPF_ATTACH_TYPE_CGROUP_INET4_RECV_ACCEPT = {
0xa82e37b3, 0xaee7, 0x11ec, {0x9a, 0x30, 0x18, 0x60, 0x24, 0x89, 0xbe, 0xee}};
__declspec(selectany)
ebpf_attach_type_t EBPF_ATTACH_TYPE_CGROUP_INET4_RECV_ACCEPT = EBPF_ATTACH_TYPE_CGROUP_INET4_RECV_ACCEPT_GUID;

#define EBPF_ATTACH_TYPE_CGROUP_INET6_RECV_ACCEPT_GUID \
{ \
0xa82e37b4, 0xaee7, 0x11ec, { 0x9a, 0x30, 0x18, 0x60, 0x24, 0x89, 0xbe, 0xee } \
}
/** @brief The programs attached to the INET6_RECV_ACCEPT hook will get invoked for
* TCP accept() calls or for the first unicast UDP packet from a unique remote
* address/port tuple.
*
* Program type: \ref EBPF_PROGRAM_TYPE_CGROUP_SOCK_ADDR
*/
__declspec(selectany) ebpf_attach_type_t EBPF_ATTACH_TYPE_CGROUP_INET6_RECV_ACCEPT = {
0xa82e37b4, 0xaee7, 0x11ec, {0x9a, 0x30, 0x18, 0x60, 0x24, 0x89, 0xbe, 0xee}};
__declspec(selectany)
ebpf_attach_type_t EBPF_ATTACH_TYPE_CGROUP_INET6_RECV_ACCEPT = EBPF_ATTACH_TYPE_CGROUP_INET6_RECV_ACCEPT_GUID;

#define EBPF_ATTACH_TYPE_CGROUP_SOCK_OPS_GUID \
{ \
0x837d02cd, 0x3251, 0x4632, { 0x8d, 0x94, 0x60, 0xd3, 0xb4, 0x57, 0x69, 0xf2 } \
}
/** @brief Attach type for handling socket event notifications.
*
* Program type: \ref EBPF_PROGRAM_TYPE_SOCK_OPS
*/
__declspec(selectany) ebpf_attach_type_t EBPF_ATTACH_TYPE_CGROUP_SOCK_OPS = {
0x837d02cd, 0x3251, 0x4632, {0x8d, 0x94, 0x60, 0xd3, 0xb4, 0x57, 0x69, 0xf2}};
__declspec(selectany) ebpf_attach_type_t EBPF_ATTACH_TYPE_CGROUP_SOCK_OPS = EBPF_ATTACH_TYPE_CGROUP_SOCK_OPS_GUID;

#define EBPF_ATTACH_TYPE_SAMPLE_GUID \
{ \
0xf788ef4b, 0x207d, 0x4dc3, { 0x85, 0xcf, 0x0f, 0x2e, 0xa1, 0x07, 0x21, 0x3c } \
}

/** @brief Attach type implemented by eBPF Sample Extension driver, used for testing.
*
* Program type: \ref EBPF_PROGRAM_TYPE_SAMPLE
* Program type: \ref EBPF_ATTACH_TYPE_SAMPLE
*/
__declspec(selectany) ebpf_attach_type_t EBPF_ATTACH_TYPE_SAMPLE = {
0xf788ef4b, 0x207d, 0x4dc3, {0x85, 0xcf, 0x0f, 0x2e, 0xa1, 0x07, 0x21, 0x3c}};
__declspec(selectany) ebpf_attach_type_t EBPF_ATTACH_TYPE_SAMPLE = EBPF_ATTACH_TYPE_SAMPLE_GUID;

#define EBPF_ATTACH_TYPE_XDP_TEST_GUID \
{ \
0x0dccc15d, 0xa5f9, 0x4dc1, { 0xac, 0x79, 0xfa, 0x25, 0xee, 0xf2, 0x15, 0xc3 } \
}
/** @brief Attach type for handling incoming packets as early as possible.
*
* Program type: \ref EBPF_PROGRAM_TYPE_XDP_TEST
*/
__declspec(selectany) ebpf_attach_type_t EBPF_ATTACH_TYPE_XDP_TEST = {
0x0dccc15d, 0xa5f9, 0x4dc1, {0xac, 0x79, 0xfa, 0x25, 0xee, 0xf2, 0x15, 0xc3}};
__declspec(selectany) ebpf_attach_type_t EBPF_ATTACH_TYPE_XDP_TEST = EBPF_ATTACH_TYPE_XDP_TEST_GUID;

//
// Program Types.
Expand Down