diff --git a/src/xdp/program.c b/src/xdp/program.c index 012f1bc2..36e0ae9a 100644 --- a/src/xdp/program.c +++ b/src/xdp/program.c @@ -238,7 +238,7 @@ XdpInvokeEbpf( XdpMd.Base.data = Va; XdpMd.Base.data_end = Va + Buffer->DataLength; XdpMd.Base.data_meta = 0; - XdpMd.Base.ingress_ifindex = IFI_UNSPECIFIED; + XdpMd.Base.ingress_ifindex = InspectionContext->IfIndex; ebpf_program_batch_invoke_function_t EbpfInvokeProgram = EbpfExtensionClientGetProgramDispatch(Client)->ebpf_program_batch_invoke_function; diff --git a/src/xdp/program.h b/src/xdp/program.h index 0d80a6b5..c80a84e7 100644 --- a/src/xdp/program.h +++ b/src/xdp/program.h @@ -15,6 +15,7 @@ typedef ebpf_execution_context_state_t XDP_INSPECTION_EBPF_CONTEXT; typedef struct _XDP_INSPECTION_CONTEXT { XDP_INSPECTION_EBPF_CONTEXT EbpfContext; XDP_REDIRECT_CONTEXT RedirectContext; + ULONG IfIndex; } XDP_INSPECTION_CONTEXT; // diff --git a/src/xdp/rx.c b/src/xdp/rx.c index 8bd20efe..b7c6cb33 100644 --- a/src/xdp/rx.c +++ b/src/xdp/rx.c @@ -1009,6 +1009,7 @@ XdpRxQueueCreate( XdpQueueSyncInitialize(&RxQueue->Sync); RxQueue->Binding = Binding; RxQueue->Key = Key; + RxQueue->InspectionContext.IfIndex = XdpIfGetIfIndex(Binding); XdpInitializeQueueInfo(&RxQueue->QueueInfo, XDP_QUEUE_TYPE_DEFAULT_RSS, QueueId); XdbgInitializeQueueEc(RxQueue); diff --git a/test/bpf/bpf.vcxproj b/test/bpf/bpf.vcxproj index 6c20ae25..b5e2453d 100644 --- a/test/bpf/bpf.vcxproj +++ b/test/bpf/bpf.vcxproj @@ -34,14 +34,16 @@ - set PATH=%PATH%;$(EbpfPackagePath)build\native\bin + xcopy $(EbpfPackagePath)build\native\bin\EbpfApi.dll $(SolutionDir)artifacts\bin\$(Platform)_$(Configuration) /Y + $(EbpfPackagePath)build\native\bin\export_program_info.exe $(SolutionDir)artifacts\bin\$(Platform)_$(Configuration)\xdp_bpfexport.exe - set PATH=%PATH%;$(EbpfPackagePath)build\native\bin $(SolutionDir)artifacts\bin\$(Platform)_$(Configuration)\xdp_bpfexport.exe --clear + $(EbpfPackagePath)build\native\bin\export_program_info.exe --clear + del $(SolutionDir)artifacts\bin\$(Platform)_$(Configuration)\ebpfapi.dll /F @@ -66,6 +68,16 @@ rmdir /s /q $(OutDir)\drop_km popd + + CppCode + $(OutDir)selective_drop.sys + + clang -g -target bpf -O2 -Werror $(ClangIncludes) -c %(Filename).c -o $(OutDir)%(Filename).o + pushd $(OutDir) + powershell -NonInteractive -ExecutionPolicy Unrestricted $(EbpfBinPath)\Convert-BpfToNative.ps1 -FileName %(Filename) -IncludeDir $(EbpfIncludePath) -Platform $(Platform) -Configuration $(Configuration) -KernelMode $true + rmdir /s /q $(OutDir)\selective_drop_km + popd + CppCode $(OutDir)l1fwd.sys diff --git a/test/bpf/selective_drop.c b/test/bpf/selective_drop.c new file mode 100644 index 00000000..d31ed3ae --- /dev/null +++ b/test/bpf/selective_drop.c @@ -0,0 +1,57 @@ +// +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +// + +#include "bpf_endian.h" +#include "bpf_helpers.h" + +// Map configured by user mode to drop packets from a specific interface. +struct +{ + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, uint32_t); + __type(value, uint32_t); + __uint(max_entries, 1); +} interface_map SEC(".maps"); + +// Map to track the number of dropped packets. +struct +{ + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, uint32_t); + __type(value, uint64_t); + __uint(max_entries, 1); +} dropped_packet_map SEC(".maps"); + +SEC("xdp/selective_drop") +int +selective_drop(xdp_md_t *ctx) +{ + int action = XDP_PASS; + int zero = 0; + + uint32_t *interface_index = bpf_map_lookup_elem(&interface_map, &zero); + if (!interface_index) { + bpf_printk("selective_drop: interface_map lookup failed."); + goto Exit; + } + + if (*interface_index == ctx->ingress_ifindex) { + action = XDP_DROP; + bpf_printk("selective_drop: interface_map lookup found matching interface %d", *interface_index); + + uint64_t *dropped_packet_count = bpf_map_lookup_elem(&dropped_packet_map, &zero); + if (dropped_packet_count) { + *dropped_packet_count += 1; + } else { + uint64_t dropped_packet_count = 1; + bpf_map_update_elem(&dropped_packet_map, &zero, &dropped_packet_count, BPF_ANY); + } + } else { + bpf_printk("selective_drop: interface_map lookup found non-matching interface %d, expected %d", *interface_index, ctx->ingress_ifindex); + } + +Exit: + return action; +} diff --git a/test/functional/lib/tests.cpp b/test/functional/lib/tests.cpp index ff5065ee..94d66eb8 100644 --- a/test/functional/lib/tests.cpp +++ b/test/functional/lib/tests.cpp @@ -4708,6 +4708,69 @@ ProgTestRunRxEbpfPayload() TEST_EQUAL(memcmp(UdpFrameV4, UdpFrameOutV4, sizeof(UdpFrameV4)), 0); } +VOID +GenericRxEbpfIfIndex() +{ + auto If = FnMpIf; + wil::unique_handle GenericMp; + wil::unique_handle FnLwf; + const UCHAR Payload[] = "GenericRxEbpfIfIndex"; + UINT32 Zero = 0; + + unique_bpf_object BpfObject = AttachEbpfXdpProgram(If, "\\bpf\\selective_drop.sys", "selective_drop"); + + GenericMp = MpOpenGeneric(If.GetIfIndex()); + FnLwf = LwfOpenDefault(If.GetIfIndex()); + + // Get the interface_map fd. + fd_t interface_map_fd = bpf_object__find_map_fd_by_name(BpfObject.get(), "interface_map"); + TEST_NOT_EQUAL(interface_map_fd, ebpf_fd_invalid); + + // Update the interface_map with the interface index of the test interface. + UINT32 IfIndex = If.GetIfIndex(); + TEST_NOT_EQUAL(IfIndex, IFI_UNSPECIFIED); + + TEST_EQUAL(0, bpf_map_update_elem(interface_map_fd, &Zero, &IfIndex, BPF_ANY)); + + std::vector Mask(sizeof(Payload), 0xFF); + LwfRxFilter(FnLwf, Payload, &Mask[0], sizeof(Payload)); + + RX_FRAME Frame; + RxInitializeFrame(&Frame, If.GetQueueId(), Payload, sizeof(Payload)); + TEST_HRESULT(MpRxEnqueueFrame(GenericMp, &Frame)); + MpRxFlush(GenericMp); + + Sleep(TEST_TIMEOUT_ASYNC_MS); + + UINT32 FrameLength = 0; + // Packet should be dropped. + TEST_EQUAL( + HRESULT_FROM_WIN32(ERROR_NOT_FOUND), + LwfRxGetFrame(FnLwf, If.GetQueueId(), &FrameLength, NULL)); + + // Validate that the dropped_packet_map contains a non-0 entry for the IfIndex. + fd_t dropped_packet_map_fd = bpf_object__find_map_fd_by_name(BpfObject.get(), "dropped_packet_map"); + TEST_NOT_EQUAL(dropped_packet_map_fd, ebpf_fd_invalid); + + UINT64 DroppedPacketCount = 0; + TEST_EQUAL(0, bpf_map_lookup_elem(dropped_packet_map_fd, &Zero, &DroppedPacketCount)); + TEST_EQUAL(DroppedPacketCount, 1); + + // Now set the ifIndex to some other value and verify that the packet is not dropped. + UINT32 OtherIfIndex = If.GetIfIndex() + 1; + TEST_EQUAL(0, bpf_map_update_elem(interface_map_fd, &Zero, &OtherIfIndex, BPF_ANY)); + + TEST_HRESULT(MpRxEnqueueFrame(GenericMp, &Frame)); + MpRxFlush(GenericMp); + + Sleep(TEST_TIMEOUT_ASYNC_MS); + + // Packet should not be dropped. + TEST_EQUAL( + HRESULT_FROM_WIN32(ERROR_MORE_DATA), + LwfRxGetFrame(FnLwf, If.GetQueueId(), &FrameLength, NULL)); +} + VOID GenericRxEbpfFragments() { diff --git a/test/functional/lib/tests.h b/test/functional/lib/tests.h index c5c7221b..37b80fa8 100644 --- a/test/functional/lib/tests.h +++ b/test/functional/lib/tests.h @@ -121,6 +121,9 @@ GenericRxEbpfPayload(); VOID ProgTestRunRxEbpfPayload(); +VOID +GenericRxEbpfIfIndex(); + VOID GenericRxEbpfFragments(); diff --git a/test/functional/taef/tests.cpp b/test/functional/taef/tests.cpp index 9bf7392c..c57b4acb 100644 --- a/test/functional/taef/tests.cpp +++ b/test/functional/taef/tests.cpp @@ -424,6 +424,10 @@ TEST_CLASS(xdpfunctionaltests) ::ProgTestRunRxEbpfPayload(); } + TEST_METHOD(GenericRxEbpfIfIndex) { + ::GenericRxEbpfIfIndex(); + } + TEST_METHOD(GenericRxEbpfFragments) { ::GenericRxEbpfFragments(); }