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();
}