summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortongzongzhen <[email protected]>2024-08-27 18:22:25 +0800
committertongzongzhen <[email protected]>2024-08-27 18:22:25 +0800
commitc1bef60e76175c7e4662506c53502fbd8cb0139b (patch)
tree4384709c1d1a4136a9245ab59e05fdbbc65fcfa4
parent5abcfe283a84bb280f71b623d3049382a28d88d8 (diff)
init dummy_ebpf
-rw-r--r--.clang-format2
-rw-r--r--dummy_ebpf/CMakeLists.txt10
-rw-r--r--dummy_ebpf/include/config.h16
-rw-r--r--dummy_ebpf/include/device.h22
-rw-r--r--dummy_ebpf/include/tap.h7
-rw-r--r--dummy_ebpf/include/xdp_prog_user.h3
-rw-r--r--dummy_ebpf/send.py15
-rw-r--r--dummy_ebpf/src/CMakeLists.txt29
-rw-r--r--dummy_ebpf/src/config.c31
-rw-r--r--dummy_ebpf/src/device.c163
-rw-r--r--dummy_ebpf/src/main.c30
-rw-r--r--dummy_ebpf/src/tap.c166
-rw-r--r--dummy_ebpf/src/xdp_prog_kernel.c49
-rw-r--r--dummy_ebpf/src/xdp_prog_user.c62
14 files changed, 605 insertions, 0 deletions
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..07d9df6
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,2 @@
+BasedOnStyle: LLVM
+ColumnLimit: 100 \ No newline at end of file
diff --git a/dummy_ebpf/CMakeLists.txt b/dummy_ebpf/CMakeLists.txt
new file mode 100644
index 0000000..b0f1f08
--- /dev/null
+++ b/dummy_ebpf/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.10)
+
+project(dummy_redirect)
+
+find_package(PkgConfig)
+pkg_check_modules(NL3 REQUIRED libnl-3.0 libnl-genl-3.0 libnl-route-3.0)
+
+include_directories(include)
+
+add_subdirectory(src) \ No newline at end of file
diff --git a/dummy_ebpf/include/config.h b/dummy_ebpf/include/config.h
new file mode 100644
index 0000000..d45e6f1
--- /dev/null
+++ b/dummy_ebpf/include/config.h
@@ -0,0 +1,16 @@
+#pragma once
+#include <linux/limits.h>
+
+#include "device.h"
+
+#define PROG_NAME_MAXSIZE 32
+
+struct config {
+ int nr_device;
+ struct device_desc devices[DEVICE_MAX_NUM];
+ char open_filename[PATH_MAX];
+ char prog_name[PROG_NAME_MAXSIZE];
+};
+
+void global_config_init();
+const struct config *global_config_get(); \ No newline at end of file
diff --git a/dummy_ebpf/include/device.h b/dummy_ebpf/include/device.h
new file mode 100644
index 0000000..dc977ab
--- /dev/null
+++ b/dummy_ebpf/include/device.h
@@ -0,0 +1,22 @@
+#pragma once
+#include <net/if.h>
+#include <stdint.h>
+
+#define DEVICE_MAX_NUM 10
+
+struct device_desc {
+ uint8_t key;
+ char device_type[20];
+ char device_name[IF_NAMESIZE];
+};
+
+const struct device {
+ int nr_device;
+ int device_fds[DEVICE_MAX_NUM];
+ int device_index[DEVICE_MAX_NUM];
+ struct device_desc device_descs[DEVICE_MAX_NUM];
+};
+
+void device_init();
+const struct device *device_inst_get();
+int xdp_device_index_get(); \ No newline at end of file
diff --git a/dummy_ebpf/include/tap.h b/dummy_ebpf/include/tap.h
new file mode 100644
index 0000000..d0016ca
--- /dev/null
+++ b/dummy_ebpf/include/tap.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include <linux/if_tun.h>
+
+int tap_alloc(const char *ifname, int flags);
+int tap_set_mac(const unsigned char *interface_name, const unsigned char *str_macaddr);
+int tap_set_ip(const unsigned char *interface_name, const unsigned char *ipaddr); \ No newline at end of file
diff --git a/dummy_ebpf/include/xdp_prog_user.h b/dummy_ebpf/include/xdp_prog_user.h
new file mode 100644
index 0000000..a423483
--- /dev/null
+++ b/dummy_ebpf/include/xdp_prog_user.h
@@ -0,0 +1,3 @@
+#pragma once
+
+struct xdp_program *load_bpf_and_xdp_attach(); \ No newline at end of file
diff --git a/dummy_ebpf/send.py b/dummy_ebpf/send.py
new file mode 100644
index 0000000..fb24d15
--- /dev/null
+++ b/dummy_ebpf/send.py
@@ -0,0 +1,15 @@
+from scapy.all import *
+
+def arp_test():
+ # 构建一个 ARP 请求数据包
+ arp_request = Ether(dst="ff:ff:ff:ff:ff:ff") / ARP(pdst="192.168.1.1")
+
+ # 在数据包负载后面追加一个不属于这个数据包的字符
+ extra_data = 'a'
+ arp_request = arp_request / Raw(load=extra_data)
+
+ # 发送 ARP 请求到 dummy0 接口
+ sendp(arp_request, iface="dummy0")
+
+if __name__ == "__main__":
+ arp_test()
diff --git a/dummy_ebpf/src/CMakeLists.txt b/dummy_ebpf/src/CMakeLists.txt
new file mode 100644
index 0000000..0dd48f6
--- /dev/null
+++ b/dummy_ebpf/src/CMakeLists.txt
@@ -0,0 +1,29 @@
+find_package(PkgConfig)
+pkg_check_modules(LIBBPF REQUIRED libbpf)
+pkg_check_modules(LIBXDP REQUIRED libxdp)
+
+find_path(ASM_TYPES_H_PATH NAMES asm/types.h PATHS /usr/include/x86_64-linux-gnu)
+if(ASM_TYPES_H_PATH)
+ message(STATUS "Found asm/types.h at ${ASM_TYPES_H_PATH}")
+ include_directories(${ASM_TYPES_H_PATH})
+else()
+ message(FATAL_ERROR "asm/types.h not found")
+endif()
+
+set(BPF_C_FILE ${CMAKE_CURRENT_SOURCE_DIR}/xdp_prog_kernel.c)
+set(BPF_O_FILE ${CMAKE_CURRENT_BINARY_DIR}/xdp_prog_kernel.o)
+add_custom_command(OUTPUT ${BPF_O_FILE}
+ COMMAND clang -g -O2 -target bpf -D__x86_64__ -I${ASM_TYPES_H_PATH} -c ${BPF_C_FILE} -o ${BPF_O_FILE}
+ COMMAND_EXPAND_LISTS
+ VERBATIM
+ DEPENDS ${BPF_C_FILE}
+ COMMENT "[clang] Building BPF file: ${BPF_C_FILE}")
+
+add_custom_target(generate_bpf_obj ALL
+ DEPENDS ${BPF_O_FILE}
+)
+
+set(SOURCE_FILES main.c config.c device.c tap.c xdp_prog_user.c)
+add_executable(main ${SOURCE_FILES})
+target_include_directories(main PRIVATE ${NL3_INCLUDE_DIRS})
+target_link_libraries(main PRIVATE ${NL3_LIBRARIES} ${LIBBPF_LIBRARIES} ${LIBXDP_LIBRARIES}) \ No newline at end of file
diff --git a/dummy_ebpf/src/config.c b/dummy_ebpf/src/config.c
new file mode 100644
index 0000000..915f14a
--- /dev/null
+++ b/dummy_ebpf/src/config.c
@@ -0,0 +1,31 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "config.h"
+
+static struct config global_conf = {};
+
+void global_config_init() {
+ // There are three devices in the configuration by default
+ global_conf.nr_device = 3;
+
+ struct device_desc *device_ref = &global_conf.devices[0];
+ snprintf(device_ref->device_type, sizeof(device_ref->device_type), "%s", "dummy");
+ snprintf(device_ref->device_name, sizeof(device_ref->device_name), "%s", "dummy0");
+
+ device_ref = &global_conf.devices[1];
+ device_ref->key = '0';
+ snprintf(device_ref->device_type, sizeof(device_ref->device_type), "%s", "tap");
+ snprintf(device_ref->device_name, sizeof(device_ref->device_name), "%s", "tap0");
+
+ device_ref = &global_conf.devices[2];
+ device_ref->key = '1';
+ snprintf(device_ref->device_type, sizeof(device_ref->device_type), "%s", "tap");
+ snprintf(device_ref->device_name, sizeof(device_ref->device_name), "%s", "tap1");
+
+ // The file where ebpf is located, and the ebpf program name
+ snprintf(global_conf.open_filename, sizeof(global_conf.open_filename), "s", "xdp_prog_kernel.o");
+ snprintf(global_conf.prog_name, sizeof(global_conf.prog_name), "s", "xdp_redirect_map_func");
+}
+
+const struct config *global_config_get() { return &global_conf; } \ No newline at end of file
diff --git a/dummy_ebpf/src/device.c b/dummy_ebpf/src/device.c
new file mode 100644
index 0000000..65c6926
--- /dev/null
+++ b/dummy_ebpf/src/device.c
@@ -0,0 +1,163 @@
+#include "device.h"
+#include "config.h"
+#include "tap.h"
+
+#include <assert.h>
+#include <linux/if.h>
+#include <linux/rtnetlink.h>
+#include <netlink/errno.h>
+#include <netlink/msg.h>
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+#include <netlink/socket.h>
+
+struct device device_inst;
+
+static int netlink_add(const char *iftype, const char *ifname) {
+ struct rtnl_link *link = rtnl_link_alloc();
+ rtnl_link_set_type(link, iftype);
+ rtnl_link_set_name(link, ifname);
+
+ struct nl_sock *sk = nl_socket_alloc();
+ nl_connect(sk, NETLINK_ROUTE);
+
+ return rtnl_link_add(sk, link, NLM_F_CREATE | NLM_F_EXCL);
+}
+
+static int netlink_change(const char *ifname, unsigned int flags) {
+ // modify from: https://github.com/thom311/libnl/blob/main/tests/test-loopback-up-down.c
+ struct nl_sock *sk;
+ struct rtnl_link *link, *change;
+ struct nl_cache *cache;
+ int err = 0;
+
+ sk = nl_socket_alloc();
+ if ((err = nl_connect(sk, NETLINK_ROUTE)) < 0) {
+ nl_perror(err, "Unable to connect socket");
+ return err;
+ }
+
+ if ((err = rtnl_link_alloc_cache(sk, AF_UNSPEC, &cache)) < 0) {
+ nl_perror(err, "Unable to allocate cache");
+ goto out;
+ }
+
+ if (!(link = rtnl_link_get_by_name(cache, ifname))) {
+ fprintf(stderr, "Interface not found\n");
+ err = 1;
+ goto out;
+ }
+
+ /* exit if the loopback interface is already activated */
+ /* After calling tap_alloc(), the tap state is already UP */
+ err = rtnl_link_get_flags(link);
+ if ((err & IFF_UP)) {
+ err = 0;
+ goto out;
+ }
+
+ change = rtnl_link_alloc();
+ rtnl_link_set_flags(change, flags);
+ if ((err = rtnl_link_change(sk, link, change, 0)) < 0) {
+ nl_perror(err, "Unable to activate lo");
+ goto out;
+ }
+
+ err = 0;
+
+out:
+ nl_socket_free(sk);
+ return err;
+}
+
+void device_create() {
+ int ret = 0;
+ memset(&device_inst, 0, sizeof(struct device));
+ const struct config *conf = global_config_get();
+
+ for (int i = 0; i < conf->nr_device; i++) {
+ const struct device_desc *src_device_ref = &conf->devices[i];
+ struct device_desc *dst_device_ref = &device_inst.device_descs[i];
+
+ dst_device_ref->key = src_device_ref->key;
+ snprintf(dst_device_ref->device_name, sizeof(dst_device_ref->device_name), "%s",
+ src_device_ref->device_name);
+ snprintf(dst_device_ref->device_type, sizeof(dst_device_ref->device_type), "%s",
+ src_device_ref->device_type);
+
+ if (strcmp(dst_device_ref->device_type, "dummy") == 0) {
+ ret = netlink_add(dst_device_ref->device_type, dst_device_ref->device_name);
+ if (ret != 0 && ret != -NLE_EXIST) {
+ fprintf(stderr, "%s\n", nl_geterror(ret));
+ goto failure;
+ }
+ } else if (strcmp(dst_device_ref->device_type, "tap") == 0) {
+ ret = tap_alloc(dst_device_ref->device_name, IFF_TAP | IFF_NO_PI);
+ if (ret <= 0) {
+ perror("tap_alloc failed");
+ goto failure;
+ }
+ device_inst.device_fds[i] = ret;
+ } else {
+ fprintf(stderr, "Currently, creation of this type of network card is not supported:%s",
+ dst_device_ref->device_type);
+ }
+ }
+
+ device_inst.nr_device = conf->nr_device;
+
+end:
+ return;
+
+failure:
+ exit(EXIT_FAILURE);
+}
+
+void device_index_get() {
+ int ifindex = 0;
+ for (unsigned int i = 0; i < device_inst.nr_device; i++) {
+ const char *dev_name = device_inst.device_descs[i].device_name;
+
+ ifindex = if_nametoindex(dev_name);
+ if (ifindex == 0) {
+ fprintf(stderr, "Failed to get %s index.", dev_name);
+ goto failure;
+ }
+
+ device_inst.device_index[i] = ifindex;
+ }
+
+failure:
+ exit(EXIT_FAILURE);
+}
+
+void device_open() {
+ int ret = 0;
+ for (unsigned int i = 0; i < device_inst.nr_device; i++) {
+ const char *dev_name = device_inst.device_descs[i].device_name;
+ ret = netlink_change(dev_name, IFF_UP);
+ if (ret != 0) {
+ fprintf(stderr, "Failed to start the device: %s", dev_name);
+ exit(EXIT_FAILURE);
+ }
+ }
+}
+
+void device_init() {
+ device_create();
+ device_index_get();
+ device_open();
+}
+
+const struct device *device_inst_get() { return &device_inst; }
+
+int xdp_device_index_get() {
+ for (unsigned int i = 0; i < device_inst.nr_device; i++) {
+ const char *device_type = device_inst.device_descs[i].device_type;
+ if (strcmp(device_type, "dummy") == 0) {
+ return device_inst.device_index[i];
+ }
+ }
+
+ return 0;
+} \ No newline at end of file
diff --git a/dummy_ebpf/src/main.c b/dummy_ebpf/src/main.c
new file mode 100644
index 0000000..981c80d
--- /dev/null
+++ b/dummy_ebpf/src/main.c
@@ -0,0 +1,30 @@
+#include <argp.h>
+#include <net/if.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "device.h"
+#include "xdp_prog_user.h"
+
+static volatile bool exiting = false;
+static void sig_handler(int sig) { exiting = true; }
+
+int main(int argc, char *argv[]) {
+ // init config
+ global_config_init();
+
+ // create and open device
+ device_init();
+
+ /* Cleaner handling of Ctrl-C */
+ signal(SIGINT, sig_handler);
+ signal(SIGTERM, sig_handler);
+
+ // load ebpf prog
+ load_bpf_and_xdp_attach();
+} \ No newline at end of file
diff --git a/dummy_ebpf/src/tap.c b/dummy_ebpf/src/tap.c
new file mode 100644
index 0000000..0c3fcd2
--- /dev/null
+++ b/dummy_ebpf/src/tap.c
@@ -0,0 +1,166 @@
+// from: https://blog.csdn.net/xxb249/article/details/86690067
+
+#include "tap.h"
+
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+int tap_alloc(const char *ifname, int flags) {
+ struct ifreq ifr;
+ int fd, err;
+ char *clonedev = "/dev/net/tun";
+
+ if ((fd = open(clonedev, O_RDWR)) < 0) {
+ return fd;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_flags = flags;
+ strcpy(ifr.ifr_name, ifname);
+ if ((err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0) {
+ close(fd);
+ return err;
+ }
+ /* 进程退出 tap0不消失 如果想删除则设置为0 */
+ if (ioctl(fd, TUNSETPERSIST, 1) < 0) {
+ perror("enabling TUNSETPERSIST");
+ exit(1);
+ }
+ return fd;
+}
+
+int tap_set_mac(const unsigned char *interface_name, const unsigned char *str_macaddr) {
+ int ret;
+ int sock_fd;
+ struct ifreq ifr;
+ unsigned int mac2bit[6];
+
+ if (interface_name == NULL || str_macaddr == NULL) {
+ return -1;
+ }
+
+ // 提取mac格式
+ sscanf((char *)str_macaddr, "%02X:%02X:%02X:%02X:%02X:%02X", (unsigned int *)&mac2bit[0],
+ (unsigned int *)&mac2bit[1], (unsigned int *)&mac2bit[2], (unsigned int *)&mac2bit[3],
+ (unsigned int *)&mac2bit[4], (unsigned int *)&mac2bit[5]);
+
+ sock_fd = socket(PF_INET, SOCK_DGRAM, 0);
+ if (sock_fd < 0) {
+ return -2;
+ }
+
+ sprintf(ifr.ifr_ifrn.ifrn_name, "%s", interface_name);
+ ifr.ifr_ifru.ifru_hwaddr.sa_family = 1;
+ ifr.ifr_ifru.ifru_hwaddr.sa_data[0] = mac2bit[0];
+ ifr.ifr_ifru.ifru_hwaddr.sa_data[1] = mac2bit[1];
+ ifr.ifr_ifru.ifru_hwaddr.sa_data[2] = mac2bit[2];
+ ifr.ifr_ifru.ifru_hwaddr.sa_data[3] = mac2bit[3];
+ ifr.ifr_ifru.ifru_hwaddr.sa_data[4] = mac2bit[4];
+ ifr.ifr_ifru.ifru_hwaddr.sa_data[5] = mac2bit[5];
+
+ ret = ioctl(sock_fd, SIOCSIFHWADDR, &ifr);
+ if (ret != 0) {
+ return -4;
+ }
+ close(sock_fd);
+ return 0;
+}
+
+int tap_set_ip(const unsigned char *interface_name, const unsigned char *ipaddr) {
+ int err;
+ int ret;
+ int socket_fd;
+ struct ifreq ifr;
+ struct sockaddr_in sin;
+
+ if (interface_name == NULL || ipaddr == NULL) {
+ return -1;
+ }
+
+ socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (socket_fd < 0) {
+ printf("Create Socket Failed.\n");
+ return -2;
+ }
+ // 指定网卡名称且up
+ sprintf(ifr.ifr_name, "%s", interface_name);
+ /* 获得接口的标志 */
+ if ((err = ioctl(socket_fd, SIOCGIFFLAGS, (void *)&ifr)) < 0) {
+ perror("ioctl SIOCGIFADDR");
+ close(socket_fd);
+ return -3;
+ }
+ ifr.ifr_flags |= IFF_UP;
+ ret = ioctl(socket_fd, SIOCSIFFLAGS, &ifr);
+ if (ret != 0) {
+ printf("Up Device %s Failed.\n", interface_name);
+ close(socket_fd);
+ return -3;
+ }
+ // 设置ip
+ memset(&sin, 0, sizeof(struct sockaddr_in));
+ sin.sin_family = AF_INET;
+ inet_pton(AF_INET, ipaddr, &sin.sin_addr.s_addr);
+ memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));
+ ret = ioctl(socket_fd, SIOCSIFADDR, &ifr);
+ if (ret != 0) {
+ printf("Set Ipaddr For Device %s Failed.\n", interface_name);
+ close(socket_fd);
+ return -4;
+ }
+
+ // 设置mask
+ sin.sin_family = AF_INET;
+ inet_pton(AF_INET, "255.255.255.0", &sin.sin_addr.s_addr);
+ memcpy(&ifr.ifr_netmask, &sin, sizeof(struct sockaddr));
+ ret = ioctl(socket_fd, SIOCSIFNETMASK, &ifr);
+
+ if (ret != 0) {
+ printf("Set NetMask For Device %s Failed.\n", interface_name);
+ close(socket_fd);
+ return -5;
+ }
+ close(socket_fd);
+ return 0;
+}
+
+#if 0
+int main() {
+ int tun_fd, nread;
+ char buffer[1500];
+
+ /* Flags: IFF_TUN - TUN device (no Ethernet headers)
+ * IFF_TAP - TAP device
+ * IFF_NO_PI - Do not provide packet information
+ */
+ tun_fd = tun_alloc("tap0", IFF_TAP | IFF_NO_PI);
+
+ if (tun_fd < 0) {
+ perror("Allocating interface");
+ exit(1);
+ }
+ tap_set_mac("tap0", "08:00:11:22:33:44");
+ tap_set_ip("tap0", "192.168.62.10");
+ while (1) {
+ nread = read(tun_fd, buffer, sizeof(buffer));
+ if (nread < 0) {
+ perror("Reading from interface");
+ close(tun_fd);
+ exit(1);
+ }
+ printf("Read %d bytes [%s] from tun/tap device\n", nread, buffer);
+ }
+ return 0;
+}
+#endif \ No newline at end of file
diff --git a/dummy_ebpf/src/xdp_prog_kernel.c b/dummy_ebpf/src/xdp_prog_kernel.c
new file mode 100644
index 0000000..3cd20f4
--- /dev/null
+++ b/dummy_ebpf/src/xdp_prog_kernel.c
@@ -0,0 +1,49 @@
+// clang-format off
+#include <linux/types.h>
+// clang-format on
+#include <bpf/bpf_endian.h>
+#include <bpf/bpf_helpers.h>
+#include <linux/bpf.h>
+#include <linux/in.h>
+
+// modify from:
+// https://github.com/xdp-project/xdp-tutorial/blob/master/packet03-redirecting/xdp_prog_kern.c
+
+struct {
+ __uint(type, BPF_MAP_TYPE_DEVMAP);
+ __type(key, __u8);
+ __type(value, int);
+ __uint(max_entries, 256);
+} tx_port SEC(".maps");
+
+SEC("xdp_redirect_map")
+int xdp_redirect_map_func(struct xdp_md *ctx) {
+ int ret = 0;
+ int action = XDP_PASS;
+ void *data = (void *)(long)ctx->data;
+ void *data_end = (void *)(long)ctx->data_end;
+
+ // According to the last character, determine which interface to forward the data packet
+ unsigned char *last_byte = (unsigned char *)(data_end - 1);
+ __u8 key = *last_byte;
+ bpf_printk("key: %d", key);
+
+ // Remove the last character
+ ret = bpf_xdp_adjust_tail(ctx, -1);
+ if (ret < 0) {
+ bpf_printk("bpf_xdp_adjust_tail failed. return code:%d", ret);
+ action = XDP_DROP;
+ }
+
+ // Redirect the packet to the endpoint referenced by map at index key.
+ ret = bpf_redirect_map(&tx_port, key, 0);
+ if (ret != XDP_REDIRECT) {
+ bpf_printk("bpf_redirect_map failed. return code:%d", ret);
+ action = XDP_DROP;
+ }
+
+out:
+ return action;
+}
+
+char _license[] SEC("license") = "GPL"; \ No newline at end of file
diff --git a/dummy_ebpf/src/xdp_prog_user.c b/dummy_ebpf/src/xdp_prog_user.c
new file mode 100644
index 0000000..559a65e
--- /dev/null
+++ b/dummy_ebpf/src/xdp_prog_user.c
@@ -0,0 +1,62 @@
+#include <errno.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <xdp/libxdp.h>
+
+#include "config.h"
+#include "device.h"
+#include "xdp_prog_user.h"
+
+struct xdp_program *load_bpf_and_xdp_attach() {
+ /* In next assignment this will be moved into ../common/ */
+ int prog_fd = -1;
+ int err;
+ struct bpf_object *obj = NULL;
+
+ const struct config *conf = global_config_get();
+ int ifindex = xdp_device_index_get();
+
+ // Clear previous prog
+ struct xdp_multiprog *mp = xdp_multiprog__get_from_ifindex(ifindex);
+ err = libxdp_get_error(mp);
+ if (!err) {
+ err = xdp_multiprog__detach(mp);
+ if (err != 0) {
+ perror("xdp_multiprog__detach failed.");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ obj = bpf_object__open(conf->open_filename);
+ if (obj == NULL) {
+ perror("bpf_object__open failed");
+ exit(EXIT_FAILURE);
+ }
+
+ struct xdp_program_opts prog_opts = {};
+ prog_opts.sz = sizeof(struct xdp_program_opts);
+ prog_opts.obj = obj;
+ prog_opts.prog_name = conf->prog_name;
+
+ struct xdp_program *prog = xdp_program__create(&prog_opts);
+ if (prog == NULL) {
+ perror("xdp_program__create failed");
+ exit(EXIT_FAILURE);
+ }
+
+ err = xdp_program__attach(prog, ifindex, XDP_MODE_UNSPEC, 0);
+ if (err != 0) {
+ perror("xdp_program__attach failed");
+ exit(EXIT_FAILURE);
+ }
+
+ prog_fd = xdp_program__fd(prog);
+ if (prog_fd < 0) {
+ fprintf(stderr, "ERR: xdp_program__fd failed: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ return prog;
+} \ No newline at end of file