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

Add minimal ebpf support for discontiguous frames #518

Merged
merged 3 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
12 changes: 9 additions & 3 deletions src/xdp/program.c
Original file line number Diff line number Diff line change
Expand Up @@ -223,12 +223,18 @@ XdpInvokeEbpf(
ASSERT((FragmentRing == NULL) || (FragmentExtension != NULL));

//
// Fragmented frames are currently not supported by eBPF.
// Fragmented frames require special handling for eBPF programs using direct
// packet access. On Linux, the program must be loaded with a specific flag
// in order to inspect discontiguous packets. On Windows, discontiguous
// frames are always inspected by default, at least until a program flag API
// is supported by eBPF-for-Windows.
//
// https://github.com/microsoft/ebpf-for-windows/issues/3576
// https://github.com/microsoft/xdp-for-windows/issues/517
//
if (FragmentRing != NULL &&
XdpGetFragmentExtension(Frame, FragmentExtension)->FragmentBufferCount != 0) {
RxAction = XDP_RX_ACTION_DROP;
goto Exit;
STAT_INC(RxQueueStats, InspectFramesDiscontiguous);
mtfriesen marked this conversation as resolved.
Show resolved Hide resolved
}

Buffer = &Frame->Buffer;
Expand Down
1 change: 1 addition & 0 deletions src/xdppcw/inc/xdppcw.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ typedef struct _XDP_PCW_RX_QUEUE {
UINT64 InspectFramesDropped;
UINT64 InspectFramesRedirected;
UINT64 InspectFramesForwarded;
UINT64 InspectFramesDiscontiguous;
} XDP_PCW_RX_QUEUE;

typedef struct _XDP_PCW_LWF_RX_QUEUE {
Expand Down
13 changes: 13 additions & 0 deletions src/xdppcw/xdppcw.man
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,19 @@
detailLevel="standard"
defaultScale="1"
/>
<counter
id="10"
uri="Microsoft.Xdp.RxQueue.InspectFramesDiscontiguous"
name="Inspection Frames Discontiguous"
nameID="2040"
field="InspectFramesDiscontiguous"
description="Frames inspected by XDP with discontiguous data."
descriptionID="2042"
type="perf_counter_rawcount"
aggregate="sum"
detailLevel="standard"
defaultScale="1"
/>
</counterSet>
<counterSet
guid="{10672701-093b-4b91-8b76-8f53afd07cd0}"
Expand Down
34 changes: 15 additions & 19 deletions test/functional/lib/tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4790,17 +4790,15 @@ GenericRxEbpfFragments()
{
auto If = FnMpIf;
unique_fnmp_handle GenericMp;
unique_fnlwf_handle FnLwf;
const UINT32 Backfill = 3;
const UINT32 Trailer = 4;
const UINT32 SplitAt = 4;
DATA_BUFFER Buffers[2] = {};
const UCHAR Payload[] = "123GenericRxEbpfFragments4321";

unique_bpf_object BpfObject = AttachEbpfXdpProgram(If, "\\bpf\\pass.sys", "pass");
unique_bpf_object BpfObject = AttachEbpfXdpProgram(If, "\\bpf\\l1fwd.sys", "l1fwd");

GenericMp = MpOpenGeneric(If.GetIfIndex());
FnLwf = LwfOpenDefault(If.GetIfIndex());

Buffers[0].DataLength = SplitAt;
Buffers[0].DataOffset = Backfill;
Expand All @@ -4811,26 +4809,24 @@ GenericRxEbpfFragments()
Buffers[1].BufferLength = Buffers[1].DataLength + Trailer;
Buffers[1].VirtualAddress = Payload + Buffers[0].BufferLength;

RX_FRAME Frame;
RxInitializeFrame(&Frame, FnMpIf.GetQueueId(), Buffers, RTL_NUMBER_OF(Buffers));

std::vector<UCHAR> Mask(sizeof(Payload) - Backfill - Trailer, 0xFF);
LwfRxFilter(FnLwf, Payload + Backfill, &Mask[0], sizeof(Payload) - Backfill - Trailer);

TEST_HRESULT(MpRxEnqueueFrame(GenericMp, &Frame));
MpRxFlush(GenericMp);

//
// We currently do not support fragments with eBPF, so this packet should
// be dropped.
// XDP-for-Windows has limited eBPF support for fragments: the first buffer
// is visible to eBPF programs, and the remaining fragments (if any) are
// inaccessible.
//
// Actions apply to the entire frame, not just to the first fragement.
//
std::vector<UCHAR> Mask((SIZE_T)Buffers[0].DataLength + Buffers[1].DataLength, 0xFF);
MpTxFilter(GenericMp, Payload + Backfill, &Mask[0], (ULONG)Mask.size());

Sleep(TEST_TIMEOUT_ASYNC_MS);
RX_FRAME Frame;
RxInitializeFrame(&Frame, If.GetQueueId(), Buffers, RTL_NUMBER_OF(Buffers));
TEST_HRESULT(MpRxEnqueueFrame(GenericMp, &Frame));
MpRxFlush(GenericMp);

UINT32 FrameLength = 0;
TEST_EQUAL(
HRESULT_FROM_WIN32(ERROR_NOT_FOUND),
LwfRxGetFrame(FnLwf, If.GetQueueId(), &FrameLength, NULL));
MpTxAllocateAndGetFrame(GenericMp, If.GetQueueId());
MpTxDequeueFrame(GenericMp, If.GetQueueId());
MpTxFlush(GenericMp);
}

VOID
Expand Down
Loading