Skip to content

Commit

Permalink
Support for xdp_tx. (microsoft#498)
Browse files Browse the repository at this point in the history
* xdp_tx

* Fix analysis error.

* update documentation.

* IPv6 tests.

* Apply suggestions from code review
  • Loading branch information
shankarseal authored Sep 10, 2021
1 parent 38952de commit acb6859
Show file tree
Hide file tree
Showing 20 changed files with 847 additions and 43 deletions.
10 changes: 10 additions & 0 deletions docs/GettingStarted.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ This will build the following binaries:
and EbpCore and NetEbpfExt drivers to be loaded.
* sample_ebpf_ext.sys: A sample eBPF extension driver that implements a test hook (for a test program type) and test helper functions.
* sample_ext_app.exe : A sample application for testing the sample extension driver.
* xdp_tests.exe : Application for testing various XDP functionalities. This requires the EbpSvc service to be running,
and the EbpCore and NetEbpfExt drivers to be loaded on a remote system to test.

and a few binaries just used for demo'ing eBPF functionality, as in the demo walkthrough discussed below:

Expand Down Expand Up @@ -153,3 +155,11 @@ Other useful options include:
2. -b to break into the debugger on test failure
3. -l to list test cases
4. Test_name to run a single test

### xdp_tests.exe
This application tests various XDP functionalities. It has the following tests:
1. Reflection Test: This tests the XDP_TX functionality. The following steps show how to run the test:
1. On the system under test, install eBPF binaries (install-ebpf.bat).
2. Load the test eBPF program by running the following commands: `netsh`, `ebpf`, `add program reflect_packet.o xdp`.
3. From a remote host, run xdp_tests.exe and in `--remote-ip` parameter pass an IPv4 or IPv6 address of an Ethernet-like interface on the system under test in string format.
4. Unload the program from system under test by running `delete program reflect_packet.o xdp` on the netsh prompt.
31 changes: 31 additions & 0 deletions ebpf-for-windows.sln
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_ext_app", "tests\sam
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "performance", "tests\performance\performance.vcxproj", "{724EB55A-CCFC-4662-92E3-B664CDA365E7}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xdp_tests", "tests\xdp\xdp_tests.vcxproj", "{07DC6181-84A2-4A14-A806-5E9AF6C929C2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM = Debug|ARM
Expand Down Expand Up @@ -1084,6 +1086,34 @@ Global
{724EB55A-CCFC-4662-92E3-B664CDA365E7}.RelWithDebInfo|x64.Build.0 = Release|x64
{724EB55A-CCFC-4662-92E3-B664CDA365E7}.RelWithDebInfo|x86.ActiveCfg = Release|Win32
{724EB55A-CCFC-4662-92E3-B664CDA365E7}.RelWithDebInfo|x86.Build.0 = Release|Win32
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.Debug|ARM.ActiveCfg = Debug|Win32
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.Debug|ARM64.ActiveCfg = Debug|Win32
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.Debug|x64.ActiveCfg = Debug|x64
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.Debug|x64.Build.0 = Debug|x64
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.Debug|x86.ActiveCfg = Debug|Win32
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.Debug|x86.Build.0 = Debug|Win32
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.MinSizeRel|ARM.ActiveCfg = Debug|Win32
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.MinSizeRel|ARM.Build.0 = Debug|Win32
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.MinSizeRel|ARM64.ActiveCfg = Debug|Win32
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.MinSizeRel|ARM64.Build.0 = Debug|Win32
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.MinSizeRel|x64.ActiveCfg = Debug|x64
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.MinSizeRel|x64.Build.0 = Debug|x64
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.MinSizeRel|x86.ActiveCfg = Debug|Win32
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.MinSizeRel|x86.Build.0 = Debug|Win32
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.Release|ARM.ActiveCfg = Release|Win32
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.Release|ARM64.ActiveCfg = Release|Win32
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.Release|x64.ActiveCfg = Release|x64
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.Release|x64.Build.0 = Release|x64
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.Release|x86.ActiveCfg = Release|Win32
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.Release|x86.Build.0 = Release|Win32
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.RelWithDebInfo|ARM.ActiveCfg = Debug|Win32
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.RelWithDebInfo|ARM.Build.0 = Debug|Win32
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.RelWithDebInfo|ARM64.ActiveCfg = Debug|Win32
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.RelWithDebInfo|ARM64.Build.0 = Debug|Win32
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.RelWithDebInfo|x64.ActiveCfg = Release|x64
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.RelWithDebInfo|x64.Build.0 = Release|x64
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.RelWithDebInfo|x86.ActiveCfg = Release|Win32
{07DC6181-84A2-4A14-A806-5E9AF6C929C2}.RelWithDebInfo|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -1122,6 +1152,7 @@ Global
{C8D46543-5AE5-4E66-B9CE-8B84588B1C9E} = {492C9B22-9237-4996-9E33-CA14D3533616}
{7358D8BD-4123-4B2D-86C0-87F6BA6CED76} = {492C9B22-9237-4996-9E33-CA14D3533616}
{724EB55A-CCFC-4662-92E3-B664CDA365E7} = {492C9B22-9237-4996-9E33-CA14D3533616}
{07DC6181-84A2-4A14-A806-5E9AF6C929C2} = {492C9B22-9237-4996-9E33-CA14D3533616}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3D5F862D-74C6-4357-9F95-0B152E33B7B8}
Expand Down
3 changes: 2 additions & 1 deletion include/ebpf_nethooks.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ typedef struct xdp_md
typedef enum _xdp_action
{
XDP_PASS = 1, ///< Allow the packet to pass.
XDP_DROP = 2 ///< Drop the packet.
XDP_DROP, ///< Drop the packet.
XDP_TX ///< Bounce the received packet back out the same NIC it arrived on.
} xdp_action_t;

/**
Expand Down
58 changes: 55 additions & 3 deletions netebpfext/net_ebpf_ext.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
#include "ebpf_windows.h"
#include "ebpf_xdp_program_data.h"

static HANDLE _net_ebpf_ext_l2_injection_handle = NULL;

static ebpf_ext_attach_hook_provider_registration_t* _ebpf_xdp_hook_provider_registration = NULL;
static ebpf_ext_attach_hook_provider_registration_t* _ebpf_bind_hook_provider_registration = NULL;
static ebpf_extension_provider_t* _ebpf_xdp_program_info_provider = NULL;
Expand Down Expand Up @@ -293,8 +295,7 @@ NTSTATUS
net_ebpf_ext_register_callouts(_Inout_ void* device_object)
/* ++
This function registers dynamic callouts and filters that
FWPM_LAYER_INBOUND_MAC_FRAME_ETHERNET layer.
This function registers WFP callouts and filters at various layers.
Callouts and filters will be removed during DriverUnload.
Expand Down Expand Up @@ -376,6 +377,11 @@ net_ebpf_ext_register_callouts(_Inout_ void* device_object)
}
is_in_transaction = FALSE;

// Create L2 injection handle.
status = FwpsInjectionHandleCreate(AF_LINK, FWPS_INJECTION_TYPE_L2, &_net_ebpf_ext_l2_injection_handle);
if (!NT_SUCCESS(status))
goto Exit;

Exit:

if (!NT_SUCCESS(status)) {
Expand Down Expand Up @@ -404,6 +410,48 @@ net_ebpf_ext_unregister_callouts(void)
FwpsCalloutUnregisterById(_net_ebpf_ext_wfp_callout_state[index].assigned_callout_id);
}
}

FwpsInjectionHandleDestroy(_net_ebpf_ext_l2_injection_handle);
}

static void
_net_ebpf_ext_l2_inject_complete(
_In_ const void* context, _Inout_ NET_BUFFER_LIST* packet_clone, BOOLEAN dispatch_level)
{
UNREFERENCED_PARAMETER(context);
FwpsFreeCloneNetBufferList(packet_clone, dispatch_level);
}

static void
_net_ebpf_ext_handle_xdp_tx(_Inout_ NET_BUFFER_LIST* packet, _In_ const FWPS_INCOMING_VALUES* incoming_fixed_values)
{
NET_BUFFER_LIST* packet_clone = NULL;
NTSTATUS status = STATUS_SUCCESS;

uint32_t interface_index =
incoming_fixed_values->incomingValue[FWPS_FIELD_INBOUND_MAC_FRAME_NATIVE_INTERFACE_INDEX].value.uint32;
uint32_t ndis_port =
incoming_fixed_values->incomingValue[FWPS_FIELD_INBOUND_MAC_FRAME_NATIVE_NDIS_PORT].value.uint32;

status = FwpsAllocateCloneNetBufferList(packet, NULL, NULL, 0, &packet_clone);
if (status != STATUS_SUCCESS)
goto Exit;

status = FwpsInjectMacSendAsync(
_net_ebpf_ext_l2_injection_handle,
NULL,
0,
FWPS_LAYER_OUTBOUND_MAC_FRAME_NATIVE,
interface_index,
ndis_port,
packet_clone,
_net_ebpf_ext_l2_inject_complete,
NULL);

if (status != STATUS_SUCCESS)
goto Exit;
Exit:
return;
}

static void
Expand All @@ -422,7 +470,7 @@ _net_ebpf_ext_layer_2_classify(
-- */
{
FWP_ACTION_TYPE action = FWP_ACTION_PERMIT;
UNREFERENCED_PARAMETER(incoming_fixed_values);

UNREFERENCED_PARAMETER(incoming_metadata_values);
UNREFERENCED_PARAMETER(classify_context);
UNREFERENCED_PARAMETER(filter);
Expand Down Expand Up @@ -459,8 +507,12 @@ _net_ebpf_ext_layer_2_classify(
case XDP_PASS:
action = FWP_ACTION_PERMIT;
break;
case XDP_TX:
_net_ebpf_ext_handle_xdp_tx(nbl, incoming_fixed_values);
// Fall through.
case XDP_DROP:
action = FWP_ACTION_BLOCK;
classify_output->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
break;
}
}
Expand Down
Loading

0 comments on commit acb6859

Please sign in to comment.