Skip to content

Commit

Permalink
socketmap add (#896)
Browse files Browse the repository at this point in the history
Co-authored-by: 张铭轩 <[email protected]>
  • Loading branch information
zhangxianyu777 and 张铭轩 authored Sep 13, 2024
1 parent eff5261 commit 484ec14
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 7 deletions.
15 changes: 11 additions & 4 deletions eBPF_Supermarket/Network_Subsystem/net_manager/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,14 @@ PROJ_CLEAN = $(addsuffix _clean,$(PROJ))
.PHONY: clean clobber distclean $(PROJ) $(PROJ_CLEAN) $(CLANG) $(LLC)

# Default Target
all: lib $(PROJ) net_manager
# all: lib $(PROJ) net_manager
all: lib $(PROJ) netmanager_kern.o netmanager_kern.skel.h net_manager

# Clean Target
clean: $(PROJ_CLEAN)
@echo; echo common; $(MAKE) -C common clean
@echo; echo lib; $(MAKE) -C lib clean
$(Q)rm -f $(USER_TARGETS) $(XDP_OBJ) $(USER_OBJ) $(COPY_LOADER) $(COPY_STATS) *.ll $(XLB_OBJS)
$(Q)rm -f $(USER_TARGETS) $(XDP_OBJ) $(USER_OBJ) $(COPY_LOADER) $(COPY_STATS) *.ll $(XLB_OBJS) netmanager_kern.skel.h

# Build Library
lib: config.mk check_submodule
Expand All @@ -73,6 +74,9 @@ $(PROJ):
# Main Target
net_manager: llvm-check $(USER_TARGETS) $(XDP_OBJ) $(COPY_LOADER) $(COPY_STATS)

netmanager_kern.skel.h: netmanager_kern.o
sudo bpftool gen skeleton netmanager_kern.o > netmanager_kern.skel.h

# Copy Loader
ifdef COPY_LOADER
$(LOADER_DIR)/$(COPY_LOADER):
Expand Down Expand Up @@ -129,9 +133,12 @@ $(COMMON_H): %.h: %.c
$(COMMON_OBJS): %.o: %.h
$(Q)$(MAKE) -C $(COMMON_DIR)

$(USER_TARGETS): %: %.c $(OBJECT_LIBBPF) $(OBJECT_LIBXDP) Makefile $(COMMON_MK) $(COMMON_OBJS) $(KERN_USER_H) $(EXTRA_DEPS) $(XLB_OBJS)
# $(USER_TARGETS): %: %.c $(OBJECT_LIBBPF) $(OBJECT_LIBXDP) Makefile $(COMMON_MK) $(COMMON_OBJS) $(KERN_USER_H) $(EXTRA_DEPS) $(XLB_OBJS)
# $(QUIET_CC)$(CC) -Wall $(CFLAGS) $(LDFLAGS) -o $@ $(COMMON_OBJS) $(XLB_OBJS) $(LIB_OBJS) \
# $< $(LDLIBS)
$(USER_TARGETS): %: %.c netmanager_kern.skel.h $(OBJECT_LIBBPF) $(OBJECT_LIBXDP) Makefile $(COMMON_MK) $(COMMON_OBJS) $(KERN_USER_H) $(EXTRA_DEPS) $(XLB_OBJS)
$(QUIET_CC)$(CC) -Wall $(CFLAGS) $(LDFLAGS) -o $@ $(COMMON_OBJS) $(XLB_OBJS) $(LIB_OBJS) \
$< $(LDLIBS)
$< $(LDLIBS)

$(XDP_OBJ): %.o: %.c Makefile $(COMMON_MK) $(KERN_USER_H) $(EXTRA_DEPS) $(OBJECT_LIBBPF)
$(QUIET_CLANG)$(CLANG) -S \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ struct config {
char *router_file;
char router_file_buf[FILE_MAXSIZE];
bool print_info;
bool socketmap_flag;
};

/* Defined in common_params.o */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ void parse_cmdline_args(int argc, char **argv,
}

/* 解析命令行参数 */
while ((opt = getopt_long(argc, argv, "hd:r:L:R:ASNFUMQ:czpq:i:m:k:g:n:tT",
while ((opt = getopt_long(argc, argv, "hd:r:L:R:ASNFUMQ:czpq:i:m:k:g:n:tTf",
long_options, &longindex)) != -1) {
switch (opt) {
case 'd':
Expand Down Expand Up @@ -316,6 +316,10 @@ void parse_cmdline_args(int argc, char **argv,
// 设置打印的标志
cfg->print_info = true;
break;
case 'f':
// 设置打印的标志
cfg->socketmap_flag = true;
break;
error:
default:
// 打印使用信息并退出
Expand Down
85 changes: 83 additions & 2 deletions eBPF_Supermarket/Network_Subsystem/net_manager/netmanager.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@ static const char *__doc__ = "XDP loader\n"

#include <net/if.h>
#include <linux/if_link.h> /* depend on kernel-headers installed */

#include <signal.h>
#include <fcntl.h>
#include "./common/common_params.h"
#include "./common/common_user_bpf_xdp.h"
#include "./common/common_libbpf.h"
#include "common_kern_user.h"

#include "netmanager_kern.skel.h"
static const char *default_filename = "netmanager_kern.o";
static const char *default_progname = "xdp_entry_state";

Expand Down Expand Up @@ -76,6 +77,9 @@ static const struct option_wrapper long_options[] = {

{{"config", no_argument, NULL, 'T' },
"config from user to kernel"},

{{"socketmap_flag", no_argument, NULL, 'f' },
"socketmap_flag"},
{{0, 0, NULL, 0 }, NULL, false}
};

Expand Down Expand Up @@ -635,13 +639,16 @@ int load_handler_mac(char* mac_filter_file){
return 0;
}

static volatile bool exiting = false;

int clear_handler(int argc, char *argv[]){
int ret = clear_map();
printf("%d rules are cleared\n", ret-1);
return 0;
}

static void sig_handler(int signo) { exiting = true; }

int main(int argc, char **argv)
{
int i;
Expand All @@ -668,6 +675,7 @@ int main(int argc, char **argv)
.router = false, //路由
.state = false, //会话保持
.clear = false, //清理
.socketmap_flag =false,
};
/* Set default BPF-ELF object file and BPF program name */
// 设置默认的BPF ELF对象文件名和BPF程序名称
Expand All @@ -677,6 +685,79 @@ int main(int argc, char **argv)
// 解析命令行参数,可能会修改程序名称等配置信息
parse_cmdline_args(argc, argv, long_options, &cfg, __doc__);

if(cfg.socketmap_flag)
{
struct netmanager_kern *skel;
signal(SIGINT, sig_handler);
signal(SIGTERM, sig_handler);
skel = netmanager_kern__open();
int cgroup_fd = open("/sys/fs/cgroup/foo", O_RDONLY);
if (cgroup_fd < 0) {
perror("Failed to open cgroup directory");
return -1;
}
if (!skel) {
fprintf(stderr, "Failed to open BPF skeleton\n");
return 1;
}

err = netmanager_kern__load(skel);
if (err) {
fprintf(stderr, "Failed to load and verify BPF skeleton\n");
goto cleanup;
}
err = netmanager_kern__attach(skel);
if (err) {
fprintf(stderr, "Failed to attach BPF skeleton\n");
goto cleanup;
}
int sock_ops_prog_fd = bpf_program__fd(skel->progs.bpf_sockmap);
if (sock_ops_prog_fd < 0) {
fprintf(stderr, "Invalid sock_ops program fd: %d\n", sock_ops_prog_fd);
return -1;
}

int msg_verdict_prog_fd = bpf_program__fd(skel->progs.bpf_redir);
if (msg_verdict_prog_fd < 0) {
fprintf(stderr, "Invalid msg_verdict program fd: %d\n", msg_verdict_prog_fd);
return -1;
}

int sock_ops_map_fd = bpf_map__fd(skel->maps.sock_ops_map);
if (sock_ops_map_fd < 0) {
fprintf(stderr, "Invalid sock_ops map fd: %d\n", sock_ops_map_fd);
return -1;
}

err = bpf_prog_attach(sock_ops_prog_fd, cgroup_fd, BPF_CGROUP_SOCK_OPS, 0);
if (err) {
fprintf(stderr, "Failed to attach bpf_sockmap program: %d\n", err);
return 1;
}

//加载并附加msg_verdict程序
err = bpf_prog_attach(msg_verdict_prog_fd, sock_ops_map_fd, BPF_SK_MSG_VERDICT, 0);
if (err) {
fprintf(stderr, "Failed to attach bpf_redir program: %d\n", err);
return 1;
}
while (!exiting) {
sleep(1);
printf("----1-----\n");
/* Ctrl-C will cause -EINTR */
if (err == -EINTR) {
err = 0;
break;
}
if (err < 0) {
printf("Error polling perf buffer: %d\n", err);
break;
}
}
cleanup:
netmanager_kern__destroy(skel);
return err < 0 ? -err : 0;
}
/* Required option */
// 检查是否提供了必需的选项
if (cfg.ifindex == -1) {
Expand Down
83 changes: 83 additions & 0 deletions eBPF_Supermarket/Network_Subsystem/net_manager/netmanager_kern.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,26 @@ struct {
__uint(max_entries, MAX_RULES);
} conn_ipv4_map SEC(".maps");

struct sock_key {
__u32 sip4; // 源 IP
__u32 dip4; // 目的 IP
__u8 family; // 协议类型
__u8 pad1; // this padding required for 64bit alignment
__u16 pad2; // else ebpf kernel verifier rejects loading of the program
__u32 pad3;
__u32 sport; // 源端口
__u32 dport; // 目的端口
} __attribute__((packed));

struct{
__uint(type, BPF_MAP_TYPE_SOCKHASH);
__type(key,struct sock_key);
__type(value, int);
__uint(max_entries, 65535);
}sock_ops_map SEC(".maps");

#define FORCE_READ(x) (*(volatile typeof(x) *)&(x))

static __always_inline
__u32 xdp_stats_record_action(struct xdp_md *ctx, __u32 action)
{
Expand Down Expand Up @@ -894,4 +914,67 @@ int xdp_entry_router(struct xdp_md *ctx)
out:
return xdp_stats_record_action(ctx, action);
}

static inline
void extract_key4_from_msg(struct sk_msg_md *msg, struct sock_key *key)
{
key->sip4 = msg->remote_ip4;
key->dip4 = msg->local_ip4;
key->family = 1;

key->dport = (bpf_htonl(msg->local_port) >> 16);
key->sport = FORCE_READ(msg->remote_port) >> 16;
}
static inline
void extract_key4_from_ops(struct bpf_sock_ops *ops, struct sock_key *key)
{
// keep ip and port in network byte order
key->dip4 = ops->remote_ip4;
key->sip4 = ops->local_ip4;
key->family = 1;

// local_port is in host byte order, and remote_port is in network byte order
key->sport = (bpf_htonl(ops->local_port) >> 16);
key->dport = FORCE_READ(ops->remote_port) >> 16;
}
static inline
void bpf_sock_ops_ipv4(struct bpf_sock_ops *skops)
{
struct sock_key key = {};
int ret;

extract_key4_from_ops(skops, &key);
ret = bpf_sock_hash_update(skops, &sock_ops_map, &key, BPF_NOEXIST);
//ret = sock_hash_update(skops, &sock_ops_map, &key, BPF_NOEXIST);
if (ret != 0) {
bpf_printk("sock_hash_update() failed, ret: %d\n", ret);
}

bpf_printk("sockmap: op %d, port %d --> %d\n", skops->op, skops->local_port, bpf_ntohl(skops->remote_port));
}

SEC("sockops") // 加载到 ELF 中的 `sockops` 区域,有 socket operations 时触发执行
int bpf_sockmap(struct bpf_sock_ops *skops)
{
switch (skops->op) {
case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: // 被动建连
case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: // 主动建连
if (skops->family == 2) { // AF_INET
bpf_sock_ops_ipv4(skops); // 将 socket 信息记录到到 sockmap
}
break;
default:
break;
}
return 0;
}
SEC("sk_msg") // 加载目标文件(ELF )中的 `sk_msg` section,`sendmsg` 系统调用时触发执行
int bpf_redir(struct sk_msg_md *msg)
{
struct sock_key key = {};
extract_key4_from_msg(msg, &key);
bpf_msg_redirect_hash(msg, &sock_ops_map, &key, BPF_F_INGRESS);
bpf_printk("bpf_msg_redirect_hash successful!");
return SK_PASS;
}
char _license[] SEC("license") = "GPL";

0 comments on commit 484ec14

Please sign in to comment.