diff --git a/src/xdp/program.c b/src/xdp/program.c index 310612e6..57cd8c0f 100644 --- a/src/xdp/program.c +++ b/src/xdp/program.c @@ -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); } Buffer = &Frame->Buffer; diff --git a/src/xdppcw/inc/xdppcw.h b/src/xdppcw/inc/xdppcw.h index 3236f049..14aa884c 100644 --- a/src/xdppcw/inc/xdppcw.h +++ b/src/xdppcw/inc/xdppcw.h @@ -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 { diff --git a/src/xdppcw/xdppcw.man b/src/xdppcw/xdppcw.man index 2db6ac56..ea47696b 100644 --- a/src/xdppcw/xdppcw.man +++ b/src/xdppcw/xdppcw.man @@ -145,6 +145,19 @@ detailLevel="standard" defaultScale="1" /> + Mask(sizeof(Payload) - Backfill - Trailer, 0xFF); - auto LwfFilter = 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 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