Skip to content

Commit

Permalink
xdp-tailcall: add XDP tailcall
Browse files Browse the repository at this point in the history
Loongarch64 does not support bpf trampoline and
freplace, so use tail call to call XDP program.

Signed-off-by: Vincent Li <[email protected]>
  • Loading branch information
vincentmli committed Jan 6, 2025
1 parent 4ad6135 commit ad2a4e6
Show file tree
Hide file tree
Showing 5 changed files with 492 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ include config.mk
UTILS := xdp-filter xdp-loader xdp-dump

ifneq ($(BPFTOOL),)
UTILS += xdp-bench xdp-monitor xdp-trafficgen xdp-synproxy xdp-dnsrrl xdp-udp xdp-dns xdp-sni xdp-geoip xdp-udpddos
UTILS += xdp-bench xdp-monitor xdp-trafficgen xdp-synproxy xdp-dnsrrl xdp-udp xdp-dns xdp-sni xdp-geoip xdp-udpddos xdp-tailcall
endif

SUBDIRS := lib $(UTILS)
Expand Down
9 changes: 9 additions & 0 deletions xdp-tailcall/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)

XDP_TARGETS := xdp_tailcall.bpf
BPF_SKEL_TARGETS := $(XDP_TARGETS)
USER_TARGETS := xdp_sni xdp_sni_log

LIB_DIR = ../lib

include $(LIB_DIR)/common.mk
78 changes: 78 additions & 0 deletions xdp-tailcall/xdp_sni.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright (c) 2024, BPFire. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>

#define MAX_DOMAIN_SIZE 63

int main(int argc, char *argv[])
{
int map_fd;
char server_name[MAX_DOMAIN_SIZE + 1] = {0};
__u8 value = 1;

// Check for proper number of arguments
if (argc != 4) {
fprintf(stderr, "Usage: %s <map_path> <add|delete> <domain>\n", argv[0]);
return 1;
}

// Reverse the input domain
strncpy(server_name, argv[3], MAX_DOMAIN_SIZE);
server_name[MAX_DOMAIN_SIZE] = '\0'; // Ensure null termination

// Open the BPF map
const char *map_path = argv[1];
map_fd = bpf_obj_get(map_path);
if (map_fd < 0) {
fprintf(stderr, "Failed to open map at %s: %s\n", map_path, strerror(errno));
return 1;
}

// Add or delete the domain based on the first argument
if (strcmp(argv[2], "add") == 0) {
// Update the map with the reversed domain name
if (bpf_map_update_elem(map_fd, server_name, &value, BPF_ANY) != 0) {
fprintf(stderr, "Failed to add domain to map: %s\n",
strerror(errno));
return 1;
}
printf("Domain %s (reversed: %s) added to denylist\n", argv[3],
server_name);
} else if (strcmp(argv[2], "delete") == 0) {
// Remove the reversed domain from the map
if (bpf_map_delete_elem(map_fd, server_name) != 0) {
fprintf(stderr,
"Failed to remove domain from map: %s\n",
strerror(errno));
return 1;
}
printf("Domain %s (reversed: %s) removed from denylist\n",
argv[3], server_name);
} else {
fprintf(stderr, "Invalid command: %s. Use 'add' or 'delete'.\n",
argv[2]);
return 1;
}

return 0;
}
83 changes: 83 additions & 0 deletions xdp-tailcall/xdp_sni_log.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <bpf/libbpf.h>
#include <bpf/bpf.h>
#include <syslog.h>

#define MAX_DOMAIN_SIZE 63

struct sni_event {
__u8 len;
__u32 src_ip; // IPv4 address
char sni[MAX_DOMAIN_SIZE + 1];
};

// No need for DNS label to dot notation for SNI.
// Instead, just copy the SNI directly for logging.
void copy_sni(char *sni, char *output, size_t len)
{
if (len > MAX_DOMAIN_SIZE) {
len = MAX_DOMAIN_SIZE; // Ensure we don't overflow
}
// Directly copy the SNI string
for (size_t i = 0; i < len; i++) {
output[i] = sni[i];
}
output[len] = '\0'; // Null-terminate
}

// Corrected handle_event function to match the signature expected by ring_buffer__new
int handle_event(void *ctx __attribute__((unused)), void *data,
size_t data_sz __attribute__((unused)))
{
struct sni_event *event = (struct sni_event *)data;

char src_ip_str[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &event->src_ip, src_ip_str, sizeof(src_ip_str));

char domain_str[MAX_DOMAIN_SIZE + 1] = { 0 }; // Buffer for SNI
copy_sni(event->sni, domain_str, event->len);

syslog(LOG_INFO, "Received SNI: %s from source IP: %s", domain_str,
src_ip_str);

return 0; // Return 0 to indicate success
}

int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "Usage: %s <path_to_ringbuf>\n", argv[0]);
return 1;
}

const char *ringbuf_path = argv[1];
struct ring_buffer *rb;
int ringbuf_fd;

openlog("sni_logger", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);

// Open the ring buffer
ringbuf_fd = bpf_obj_get(ringbuf_path);
if (ringbuf_fd < 0) {
perror("Failed to open ring buffer");
return 1;
}

// Set up ring buffer polling with the corrected function signature
rb = ring_buffer__new(ringbuf_fd, handle_event, NULL, NULL);
if (!rb) {
perror("Failed to create ring buffer");
return 1;
}

// Poll the ring buffer
while (1) {
ring_buffer__poll(rb, -1); // Block indefinitely
}

ring_buffer__free(rb);
closelog();
return 0;
}
Loading

0 comments on commit ad2a4e6

Please sign in to comment.