add ingress interface index to xdp context. (#623)

* add ingress interface index to xdp context.

* Address PR feedback.

Co-authored-by: Dave Thaler <dthaler@microsoft.com>
Co-authored-by: Alan Jowett <alanjo@microsoft.com>
This commit is contained in:
Shankar Seal 2021-10-04 09:53:42 -07:00 коммит произвёл GitHub
Родитель 9a7eebd993
Коммит 97bd9cf7f6
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
7 изменённых файлов: 68 добавлений и 23 удалений

Просмотреть файл

@ -9,12 +9,13 @@
// XDP hook. We use "struct xdp_md" for cross-platform compatibility.
typedef struct xdp_md
{
void* data; ///< Pointer to start of packet data.
void* data_end; ///< Pointer to end of packet data.
uint64_t data_meta; ///< Packet metadata.
void* data; ///< Pointer to start of packet data.
void* data_end; ///< Pointer to end of packet data.
uint64_t data_meta; ///< Packet metadata.
uint32_t ingress_ifindex; ///< Ingress interface index.
/* size: 12, cachelines: 1, members: 3 */
/* last cacheline: 12 bytes */
/* size: 26, cachelines: 1, members: 4 */
/* last cacheline: 26 bytes */
} xdp_md_t;
typedef enum _xdp_action

Просмотреть файл

@ -303,6 +303,9 @@ net_ebpf_ext_layer_2_classify(
goto Done;
}
net_xdp_ctx.ingress_ifindex =
incoming_fixed_values->incomingValue[FWPS_FIELD_INBOUND_MAC_FRAME_NATIVE_INTERFACE_INDEX].value.uint32;
net_xdp_ctx.original_nbl = nbl;
net_buffer = NET_BUFFER_LIST_FIRST_NB(nbl);

Просмотреть файл

@ -26,7 +26,7 @@
#define DROP_PACKET_PROGRAM_COUNT 1
#define BIND_MONITOR_PROGRAM_COUNT 1
#define DROP_PACKET_MAP_COUNT 1
#define DROP_PACKET_MAP_COUNT 2
#define BIND_MONITOR_MAP_COUNT 2
static service_install_helper

Просмотреть файл

@ -226,7 +226,7 @@ droppacket_test(ebpf_execution_type_t execution_type)
error_message = nullptr;
}
REQUIRE(result == EBPF_SUCCESS);
fd_t port_map_fd = bpf_object__find_map_fd_by_name(object, "port_map");
fd_t dropped_packet_map_fd = bpf_object__find_map_fd_by_name(object, "dropped_packet_map");
REQUIRE(hook.attach_link(program_fd, &link) == EBPF_SUCCESS);
@ -234,7 +234,7 @@ droppacket_test(ebpf_execution_type_t execution_type)
uint32_t key = 0;
uint64_t value = 1000;
REQUIRE(bpf_map_update_elem(port_map_fd, &key, &value, EBPF_ANY) == EBPF_SUCCESS);
REQUIRE(bpf_map_update_elem(dropped_packet_map_fd, &key, &value, EBPF_ANY) == EBPF_SUCCESS);
// Test that we drop the packet and increment the map
xdp_md_t ctx{packet.data(), packet.data() + packet.size()};
@ -243,12 +243,12 @@ droppacket_test(ebpf_execution_type_t execution_type)
REQUIRE(hook.fire(&ctx, &hook_result) == EBPF_SUCCESS);
REQUIRE(hook_result == 2);
REQUIRE(bpf_map_lookup_elem(port_map_fd, &key, &value) == EBPF_SUCCESS);
REQUIRE(bpf_map_lookup_elem(dropped_packet_map_fd, &key, &value) == EBPF_SUCCESS);
REQUIRE(value == 1001);
REQUIRE(bpf_map_delete_elem(port_map_fd, &key) == EBPF_SUCCESS);
REQUIRE(bpf_map_delete_elem(dropped_packet_map_fd, &key) == EBPF_SUCCESS);
REQUIRE(bpf_map_lookup_elem(port_map_fd, &key, &value) == EBPF_SUCCESS);
REQUIRE(bpf_map_lookup_elem(dropped_packet_map_fd, &key, &value) == EBPF_SUCCESS);
REQUIRE(value == 0);
packet = prepare_udp_packet(10, ETHERNET_TYPE_IPV4);
@ -257,9 +257,27 @@ droppacket_test(ebpf_execution_type_t execution_type)
REQUIRE(hook.fire(&ctx2, &hook_result) == EBPF_SUCCESS);
REQUIRE(hook_result == 1);
REQUIRE(bpf_map_lookup_elem(port_map_fd, &key, &value) == EBPF_SUCCESS);
REQUIRE(bpf_map_lookup_elem(dropped_packet_map_fd, &key, &value) == EBPF_SUCCESS);
REQUIRE(value == 0);
fd_t interface_index_map_fd = bpf_object__find_map_fd_by_name(object, "interface_index_map");
uint32_t if_index = 17;
REQUIRE(bpf_map_update_elem(interface_index_map_fd, &key, &if_index, EBPF_ANY) == EBPF_SUCCESS);
packet = prepare_udp_packet(0, ETHERNET_TYPE_IPV4);
// Fire a 0-length UDP packet on the interface index in the map, which should be dropped.
xdp_md_t ctx3{packet.data(), packet.data() + packet.size(), 0, if_index};
REQUIRE(hook.fire(&ctx3, &hook_result) == EBPF_SUCCESS);
REQUIRE(hook_result == 2);
REQUIRE(bpf_map_lookup_elem(dropped_packet_map_fd, &key, &value) == EBPF_SUCCESS);
REQUIRE(value == 1);
// Fire a 0-length packet on any interface that is not in the map, which should be allowed.
xdp_md_t ctx4{packet.data(), packet.data() + packet.size(), 0, if_index + 1};
REQUIRE(hook.fire(&ctx4, &hook_result) == EBPF_SUCCESS);
REQUIRE(hook_result == 1);
REQUIRE(bpf_map_lookup_elem(dropped_packet_map_fd, &key, &value) == EBPF_SUCCESS);
REQUIRE(value == 1);
hook.detach_link(link);
hook.close_link(link);

Просмотреть файл

@ -123,7 +123,7 @@ TEST_CASE("show verification droppacket.o", "[netsh][verification]")
"\n"
"0 errors\n"
"Verification succeeded\n"
"Program terminates within 114 instructions\n");
"Program terminates within 151 instructions\n");
}
TEST_CASE("show verification droppacket_unsafe.o", "[netsh][verification]")

Просмотреть файл

@ -10,19 +10,36 @@
#include "ebpf.h"
SEC("maps")
ebpf_map_definition_in_file_t port_map = {
ebpf_map_definition_in_file_t dropped_packet_map = {
.size = sizeof(ebpf_map_definition_in_file_t),
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(uint32_t),
.value_size = sizeof(uint64_t),
.max_entries = 1};
SEC("maps")
ebpf_map_definition_in_file_t interface_index_map = {
.size = sizeof(ebpf_map_definition_in_file_t),
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(uint32_t),
.value_size = sizeof(uint32_t),
.max_entries = 1};
SEC("xdp")
int
DropPacket(xdp_md_t* ctx)
{
int rc = XDP_PASS;
ETHERNET_HEADER* eth = NULL;
long key = 0;
uint32_t* interface_index = bpf_map_lookup_elem(&interface_index_map, &key);
if (interface_index != NULL) {
if (ctx->ingress_ifindex != *interface_index) {
// Not interested in packets indicated over this interfce.
goto Done;
}
}
if ((char*)ctx->data + sizeof(ETHERNET_HEADER) + sizeof(IPV4_HEADER) + sizeof(UDP_HEADER) > (char*)ctx->data_end)
goto Done;
@ -38,8 +55,7 @@ DropPacket(xdp_md_t* ctx)
goto Done;
UDP_HEADER* udp_header = (UDP_HEADER*)((char*)ipv4_header + sizeof(uint32_t) * ipv4_header->HeaderLength);
if (ntohs(udp_header->length) <= sizeof(UDP_HEADER)) {
long key = 0;
long* count = bpf_map_lookup_elem(&port_map, &key);
long* count = bpf_map_lookup_elem(&dropped_packet_map, &key);
if (count)
*count = (*count + 1);
rc = XDP_DROP;

Просмотреть файл

@ -47,7 +47,7 @@ TEST_CASE("libbpf program", "[libbpf]")
REQUIRE(fd2 == program_fd);
size_t size = bpf_program__size(program);
REQUIRE(size == 272);
REQUIRE(size == 376);
REQUIRE(bpf_program__next(program, object) == nullptr);
REQUIRE(bpf_program__prev(program, object) == nullptr);
@ -168,17 +168,24 @@ TEST_CASE("libbpf map", "[libbpf]")
REQUIRE(result == 0);
REQUIRE(object != nullptr);
// Get the first (and only) map.
// Get the first map.
struct bpf_map* map = bpf_map__next(nullptr, object);
REQUIRE(map != nullptr);
// Verify that it's the only map.
REQUIRE(bpf_map__next(map, object) == nullptr);
// Verify that there are no maps before this.
REQUIRE(bpf_map__prev(map, object) == nullptr);
REQUIRE(bpf_map__prev(nullptr, object) == map);
// Get the next map.
struct bpf_map* map2 = bpf_map__next(map, object);
REQUIRE(map2 != nullptr);
REQUIRE(bpf_map__prev(map2, object) == map);
// Verify that there are no other maps after this.
REQUIRE(bpf_map__next(map2, object) == nullptr);
REQUIRE(bpf_map__prev(nullptr, object) == map2);
const char* name = bpf_map__name(map);
REQUIRE(strcmp(name, "port_map") == 0);
REQUIRE(strcmp(name, "dropped_packet_map") == 0);
REQUIRE(bpf_map__type(map) == BPF_MAP_TYPE_ARRAY);
REQUIRE(bpf_map__key_size(map) == 4);
REQUIRE(bpf_map__value_size(map) == 8);
@ -962,7 +969,7 @@ TEST_CASE("bpf_obj_get_info_by_fd", "[libbpf]")
REQUIRE(bpf_obj_get_info_by_fd(program_fd, &program_info, &program_info_size) == 0);
REQUIRE(program_info_size == sizeof(program_info));
REQUIRE(strcmp(program_info.name, program_name) == 0);
REQUIRE(program_info.nr_map_ids == 1);
REQUIRE(program_info.nr_map_ids == 2);
// Fetch info about the attachment and verify it matches what we'd expect.
uint32_t link_id;