Skip to content

Commit

Permalink
Populate ingress_ifindex in xdp_md struct. (#449)
Browse files Browse the repository at this point in the history
* fix

* add tests

* export program info

* delete ebpfapi post build

* fix tests

* code cleanup

* cr comment
  • Loading branch information
saxena-anurag authored Jan 26, 2024
1 parent f026933 commit c10f37f
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 3 deletions.
2 changes: 1 addition & 1 deletion src/xdp/program.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions src/xdp/program.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

//
Expand Down
1 change: 1 addition & 0 deletions src/xdp/rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
16 changes: 14 additions & 2 deletions test/bpf/bpf.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,16 @@
<ItemDefinitionGroup>
<PreBuildEvent>
<Command>
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
</Command>
</PreBuildEvent>
<PostBuildEvent>
<Command>
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
</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
Expand All @@ -66,6 +68,16 @@
rmdir /s /q $(OutDir)\drop_km
popd</Command>
</CustomBuild>
<CustomBuild Include="selective_drop.c">
<FileType>CppCode</FileType>
<Outputs>$(OutDir)selective_drop.sys</Outputs>
<Command>
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</Command>
</CustomBuild>
<CustomBuild Include="l1fwd.c">
<FileType>CppCode</FileType>
<Outputs>$(OutDir)l1fwd.sys</Outputs>
Expand Down
57 changes: 57 additions & 0 deletions test/bpf/selective_drop.c
Original file line number Diff line number Diff line change
@@ -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;
}
63 changes: 63 additions & 0 deletions test/functional/lib/tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<UCHAR> 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()
{
Expand Down
3 changes: 3 additions & 0 deletions test/functional/lib/tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ GenericRxEbpfPayload();
VOID
ProgTestRunRxEbpfPayload();

VOID
GenericRxEbpfIfIndex();

VOID
GenericRxEbpfFragments();

Expand Down
4 changes: 4 additions & 0 deletions test/functional/taef/tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,10 @@ TEST_CLASS(xdpfunctionaltests)
::ProgTestRunRxEbpfPayload();
}

TEST_METHOD(GenericRxEbpfIfIndex) {
::GenericRxEbpfIfIndex();
}

TEST_METHOD(GenericRxEbpfFragments) {
::GenericRxEbpfFragments();
}
Expand Down

0 comments on commit c10f37f

Please sign in to comment.