mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-10-29 09:32:34 +00:00
@@ -1,30 +0,0 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=ubpf
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_LICENSE:=GPL-2.0+
|
||||
PKG_LICENSE_FILES:=
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
include $(INCLUDE_DIR)/cmake.mk
|
||||
|
||||
define Package/ubpf
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
DEPENDS:=+libubox +libbpf +libnl-tiny
|
||||
TITLE:=eBPF loader
|
||||
endef
|
||||
|
||||
TARGET_CFLAGS += \
|
||||
-I$(STAGING_DIR)/usr/include \
|
||||
-I$(STAGING_DIR)/usr/include/libnl-tiny
|
||||
|
||||
define Package/ubpf/install
|
||||
$(INSTALL_DIR) $(1)/sbin
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/xdpload $(1)/sbin/
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/xdplist $(1)/sbin/
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/uxdp $(1)/sbin/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,ubpf))
|
||||
@@ -1,25 +0,0 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
PROJECT(ustatus C)
|
||||
INCLUDE(GNUInstallDirs)
|
||||
ADD_DEFINITIONS(-Os -ggdb -Wall -Werror --std=gnu99 -Wmissing-declarations -D__KERNEL__)
|
||||
|
||||
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
|
||||
|
||||
ADD_EXECUTABLE(xdpload xdpload.c xdp.c map.c prog.c net.c)
|
||||
TARGET_LINK_LIBRARIES(xdpload bpf nl-tiny)
|
||||
INSTALL(TARGETS xdpload
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR}
|
||||
)
|
||||
|
||||
ADD_EXECUTABLE(xdplist xdplist.c prog.c net.c map.c)
|
||||
TARGET_LINK_LIBRARIES(xdplist bpf nl-tiny)
|
||||
INSTALL(TARGETS xdplist
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR}
|
||||
)
|
||||
|
||||
ADD_EXECUTABLE(uxdp uxdp.c prog.c net.c map.c)
|
||||
TARGET_LINK_LIBRARIES(uxdp bpf nl-tiny)
|
||||
INSTALL(TARGETS uxdp
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR}
|
||||
)
|
||||
@@ -1,83 +0,0 @@
|
||||
#include "uxdp.h"
|
||||
|
||||
void
|
||||
map_find(struct xdp_map *lookup, __u32 map)
|
||||
{
|
||||
__u32 id = 0;
|
||||
int err;
|
||||
|
||||
while (true) {
|
||||
struct bpf_map_info info = {};
|
||||
__u32 len = sizeof(info);
|
||||
int fd;
|
||||
|
||||
err = bpf_map_get_next_id(id, &id);
|
||||
if (err) {
|
||||
if (errno == ENOENT)
|
||||
break;
|
||||
fprintf(stderr, "bpf_map_get_next_id failed\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (id != map)
|
||||
continue;
|
||||
|
||||
fd = bpf_map_get_fd_by_id(id);
|
||||
if (fd < 0) {
|
||||
if (errno == ENOENT)
|
||||
continue;
|
||||
fprintf(stderr, "bpf_map_get_fd_by_id failed\n");
|
||||
break;
|
||||
}
|
||||
|
||||
err = bpf_obj_get_info_by_fd(fd, &info, &len);
|
||||
if (err) {
|
||||
fprintf(stderr, "bpf_obj_get_info_by_fd failed\n");
|
||||
close(fd);
|
||||
break;
|
||||
}
|
||||
if (!lookup) {
|
||||
fprintf(stderr, "\t\t%u: %s\n", info.id, *info.name ? info.name : "(unknown)");
|
||||
goto next;
|
||||
}
|
||||
if (!*info.name)
|
||||
goto next;
|
||||
if (strcmp(lookup->map, info.name))
|
||||
goto next;
|
||||
memcpy(&lookup->map_info, &info, sizeof(info));
|
||||
lookup->map_fd = fd;
|
||||
lookup->map_id = id;
|
||||
continue;
|
||||
next:
|
||||
close(fd);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
map_lookup(struct xdp_map *lookup)
|
||||
{
|
||||
net_find(lookup);
|
||||
if (!lookup->map_fd)
|
||||
return -1;
|
||||
if (map_verify(&lookup->map_info, &lookup->map_want))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
map_verify(struct bpf_map_info *map, struct bpf_map_info *exp)
|
||||
{
|
||||
if (exp->key_size && exp->key_size != map->key_size)
|
||||
return -1;
|
||||
if (exp->value_size && exp->value_size != map->value_size)
|
||||
return -1;
|
||||
if (exp->max_entries && exp->max_entries != map->max_entries)
|
||||
return -1;
|
||||
if (exp->type && exp->type != map->type)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
#include <unl.h>
|
||||
|
||||
#include "uxdp.h"
|
||||
|
||||
static struct unl unl;
|
||||
|
||||
static int
|
||||
getlink_recv(struct nl_msg *msg, void *arg)
|
||||
{
|
||||
struct xdp_map *lookup = (struct xdp_map *) arg;
|
||||
struct ifinfomsg *ifi = nlmsg_data(msg->nm_nlh);
|
||||
struct nlattr *tb[IFLA_MAX + 1] = {};
|
||||
struct nlattr *xdp[IFLA_XDP_MAX + 1] = {};
|
||||
unsigned char mode;
|
||||
char *ifname;
|
||||
|
||||
if (!nlmsg_valid_hdr(msg->nm_nlh, sizeof(*ifi)) || ifi->ifi_family != AF_UNSPEC)
|
||||
return NL_SKIP;
|
||||
|
||||
nlmsg_parse(msg->nm_nlh, sizeof(*ifi), tb, __IFLA_MAX - 1, NULL);
|
||||
if (!tb[IFLA_IFNAME] || !tb[IFLA_XDP])
|
||||
return NL_SKIP;
|
||||
ifname = nla_get_string(tb[IFLA_IFNAME]);
|
||||
if (nla_parse_nested(xdp, IFLA_XDP_MAX, tb[IFLA_XDP], NULL))
|
||||
return NL_SKIP;
|
||||
|
||||
if (!xdp[IFLA_XDP_ATTACHED])
|
||||
return NL_SKIP;
|
||||
|
||||
mode = nla_get_u8(xdp[IFLA_XDP_ATTACHED]);
|
||||
if (mode == XDP_ATTACHED_NONE)
|
||||
return NL_SKIP;
|
||||
switch(mode) {
|
||||
case XDP_ATTACHED_MULTI:
|
||||
fprintf(stderr, "%s:%s[%d]XDP_ATTACHED_MULTI not supported yet\n", __FILE__, __func__, __LINE__);
|
||||
break;
|
||||
case XDP_ATTACHED_DRV:
|
||||
case XDP_ATTACHED_SKB:
|
||||
case XDP_ATTACHED_HW:
|
||||
if (!lookup)
|
||||
fprintf(stderr, "%s\n", ifname);
|
||||
prog_find(lookup, nla_get_u32(xdp[IFLA_XDP_PROG_ID]));
|
||||
break;
|
||||
}
|
||||
return NL_OK;
|
||||
}
|
||||
|
||||
void
|
||||
net_find(struct xdp_map *lookup)
|
||||
{
|
||||
struct nl_msg *msg;
|
||||
|
||||
msg = unl_rtnl_msg(&unl, RTM_GETLINK, true);
|
||||
msg->nm_nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
|
||||
unl_request(&unl, msg, getlink_recv, lookup);
|
||||
}
|
||||
|
||||
static void __attribute__((constructor))
|
||||
rtnl_init(void)
|
||||
{
|
||||
if (unl_rtnl_init(&unl))
|
||||
fprintf(stderr, "failed to open rtnl\n");
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
#include "uxdp.h"
|
||||
|
||||
static inline __u64 ptr_to_u64(const void *ptr)
|
||||
{
|
||||
return (__u64)(unsigned long)ptr;
|
||||
}
|
||||
|
||||
void
|
||||
prog_find(struct xdp_map *lookup, __u32 prog)
|
||||
{
|
||||
__u32 id = 0;
|
||||
|
||||
while(true) {
|
||||
struct bpf_prog_info info = {};
|
||||
__u32 len = sizeof(info);
|
||||
int err;
|
||||
int fd;
|
||||
|
||||
if (bpf_prog_get_next_id(id, &id)) {
|
||||
if (errno != ENOENT)
|
||||
fprintf(stderr, "bpf_prog_get_next_id failed\n");
|
||||
break;
|
||||
}
|
||||
if (id != prog)
|
||||
continue;
|
||||
fd = bpf_prog_get_fd_by_id(id);
|
||||
if (fd < 0) {
|
||||
if (errno == ENOENT)
|
||||
continue;
|
||||
fprintf(stderr, "bpf_prog_get_fd_by_id failed\n");
|
||||
break;
|
||||
}
|
||||
|
||||
err = bpf_obj_get_info_by_fd(fd, &info, &len);
|
||||
if (err) {
|
||||
fprintf(stderr, "bpf_obj_get_info_by_fd failed\n");
|
||||
close(fd);
|
||||
break;
|
||||
}
|
||||
if (info.name && !lookup)
|
||||
fprintf(stderr, "\t%d: %s\n", id, info.name);
|
||||
if (info.nr_map_ids) {
|
||||
struct bpf_prog_info maps = {};
|
||||
__u32 len = sizeof(info);
|
||||
__u32 map_ids[info.nr_map_ids];
|
||||
unsigned int i;
|
||||
int err;
|
||||
|
||||
maps.nr_map_ids = info.nr_map_ids;
|
||||
maps.map_ids = ptr_to_u64(map_ids);
|
||||
|
||||
err = bpf_obj_get_info_by_fd(fd, &maps, &len);
|
||||
if (err || !maps.nr_map_ids) {
|
||||
fprintf(stderr, "failed to get maps\n");
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < info.nr_map_ids; i++)
|
||||
map_find(lookup, map_ids[i]);
|
||||
}
|
||||
|
||||
if (!lookup)
|
||||
fprintf(stderr, "\n");
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,172 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#include "uxdp.h"
|
||||
|
||||
struct datarec {
|
||||
__u64 rx_packets;
|
||||
};
|
||||
|
||||
#ifndef XDP_ACTION_MAX
|
||||
#define XDP_ACTION_MAX (XDP_REDIRECT + 1)
|
||||
#endif
|
||||
|
||||
#define NANOSEC_PER_SEC 1000000000 /* 10^9 */
|
||||
static __u64 gettime(void)
|
||||
{
|
||||
struct timespec t;
|
||||
int res;
|
||||
|
||||
res = clock_gettime(CLOCK_MONOTONIC, &t);
|
||||
if (res < 0) {
|
||||
fprintf(stderr, "Error with gettimeofday! (%i)\n", res);
|
||||
exit(-1);
|
||||
}
|
||||
return (__u64) t.tv_sec * NANOSEC_PER_SEC + t.tv_nsec;
|
||||
}
|
||||
|
||||
struct record {
|
||||
__u64 timestamp;
|
||||
struct datarec total; /* defined in common_kern_user.h */
|
||||
};
|
||||
|
||||
struct stats_record {
|
||||
struct record stats[1]; /* Assignment#2: Hint */
|
||||
};
|
||||
|
||||
static double calc_period(struct record *r, struct record *p)
|
||||
{
|
||||
double period_ = 0;
|
||||
__u64 period = 0;
|
||||
|
||||
period = r->timestamp - p->timestamp;
|
||||
if (period > 0)
|
||||
period_ = ((double) period / NANOSEC_PER_SEC);
|
||||
|
||||
return period_;
|
||||
}
|
||||
|
||||
static void stats_print(struct stats_record *stats_rec,
|
||||
struct stats_record *stats_prev)
|
||||
{
|
||||
struct record *rec, *prev;
|
||||
double period;
|
||||
__u64 packets;
|
||||
double pps; /* packets per sec */
|
||||
|
||||
/* Assignment#2: Print other XDP actions stats */
|
||||
{
|
||||
char *fmt = "%-12s %'11lld pkts (%'10.0f pps)"
|
||||
//" %'11lld Kbytes (%'6.0f Mbits/s)"
|
||||
" period:%f\n";
|
||||
const char *action = "";
|
||||
rec = &stats_rec->stats[0];
|
||||
prev = &stats_prev->stats[0];
|
||||
|
||||
period = calc_period(rec, prev);
|
||||
if (period == 0)
|
||||
return;
|
||||
|
||||
packets = rec->total.rx_packets - prev->total.rx_packets;
|
||||
pps = packets / period;
|
||||
|
||||
printf(fmt, action, rec->total.rx_packets, pps, period);
|
||||
}
|
||||
}
|
||||
|
||||
/* BPF_MAP_TYPE_ARRAY */
|
||||
static void map_get_value_array(int fd, __u32 key, struct datarec *value)
|
||||
{
|
||||
if ((bpf_map_lookup_elem(fd, &key, value)) != 0) {
|
||||
fprintf(stderr,
|
||||
"ERR: bpf_map_xdp_map_elem failed key:0x%X\n", key);
|
||||
}
|
||||
}
|
||||
|
||||
static bool map_collect(int fd, __u32 map_type, __u32 key, struct record *rec)
|
||||
{
|
||||
struct datarec value;
|
||||
|
||||
/* Get time as close as possible to reading map contents */
|
||||
rec->timestamp = gettime();
|
||||
|
||||
switch (map_type) {
|
||||
case BPF_MAP_TYPE_ARRAY:
|
||||
map_get_value_array(fd, key, &value);
|
||||
break;
|
||||
case BPF_MAP_TYPE_PERCPU_ARRAY:
|
||||
/* fall-through */
|
||||
default:
|
||||
fprintf(stderr, "ERR: Unknown map_type(%u) cannot handle\n",
|
||||
map_type);
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Assignment#1: Add byte counters */
|
||||
rec->total.rx_packets = value.rx_packets;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void stats_collect(int map_fd, __u32 map_type,
|
||||
struct stats_record *stats_rec)
|
||||
{
|
||||
/* Assignment#2: Collect other XDP actions stats */
|
||||
__u32 key = XDP_PASS;
|
||||
|
||||
map_collect(map_fd, map_type, key, &stats_rec->stats[0]);
|
||||
}
|
||||
|
||||
static void stats_poll(int map_fd, __u32 map_type, int interval)
|
||||
{
|
||||
struct stats_record prev, record = { 0 };
|
||||
|
||||
/* Get initial reading quickly */
|
||||
stats_collect(map_fd, map_type, &record);
|
||||
usleep(1000000/4);
|
||||
|
||||
while (1) {
|
||||
prev = record; /* struct copy */
|
||||
stats_collect(map_fd, map_type, &record);
|
||||
stats_print(&record, &prev);
|
||||
sleep(interval);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct xdp_map xdp_map = {
|
||||
.prog = "xdp_stats1_func",
|
||||
.map = "xdp_stats_map",
|
||||
.map_want = {
|
||||
.key_size = sizeof(__u32),
|
||||
.value_size = sizeof(struct datarec),
|
||||
.max_entries = XDP_ACTION_MAX,
|
||||
},
|
||||
};
|
||||
int interval = 2;
|
||||
int ch;
|
||||
|
||||
while ((ch = getopt(argc, argv, "d:f:p:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'd':
|
||||
xdp_map.net = optarg;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Invalid argument\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
if (!xdp_map.net) {
|
||||
fprintf(stderr, "invalid arguments\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (map_lookup(&xdp_map)) {
|
||||
fprintf(stderr, "failed to xdp_map map\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
stats_poll(xdp_map.map_fd, xdp_map.map_info.type, interval);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#include "uxdp.h"
|
||||
|
||||
|
||||
#define SAMPLE_SIZE 64
|
||||
|
||||
static void print_bpf_output(void *ctx, int cpu, void *data, __u32 size)
|
||||
{
|
||||
struct {
|
||||
__u16 cookie;
|
||||
__u16 pkt_len;
|
||||
__u8 pkt_data[SAMPLE_SIZE];
|
||||
} __attribute__((packed)) *e = data;
|
||||
int i;
|
||||
|
||||
fprintf(stderr, "%s:%s[%d]\n", __FILE__, __func__, __LINE__);
|
||||
if (e->cookie != 0xdead) {
|
||||
printf("BUG cookie %x sized %d\n", e->cookie, size);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Pkt len: %-5d bytes. Ethernet hdr: ", e->pkt_len);
|
||||
for (i = 0; i < 14 && i < e->pkt_len; i++)
|
||||
printf("%02x ", e->pkt_data[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct xdp_map pkt_map = {
|
||||
.prog = "uxdp_prog",
|
||||
.map = "uxdp_pkts",
|
||||
.map_want = {
|
||||
.key_size = sizeof(__u32),
|
||||
.value_size = sizeof(__u32),
|
||||
.max_entries = 8,
|
||||
},
|
||||
};
|
||||
struct perf_buffer_opts pb_opts = {
|
||||
.sample_cb = print_bpf_output,
|
||||
};
|
||||
struct perf_buffer *pb;
|
||||
int ch;
|
||||
int err;
|
||||
|
||||
while ((ch = getopt(argc, argv, "d:f:p:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'd':
|
||||
pkt_map.net = optarg;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Invalid argument\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
if (!pkt_map.net) {
|
||||
fprintf(stderr, "invalid arguments\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (map_lookup(&pkt_map)) {
|
||||
fprintf(stderr, "failed to xdp_map map\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pb = perf_buffer__new(pkt_map.map_fd, 8, &pb_opts);
|
||||
err = libbpf_get_error(pb);
|
||||
if (err) {
|
||||
perror("perf_buffer setup failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (perf_buffer__poll(pb, 1000) >= 0) {
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <locale.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
#include <linux/limits.h>
|
||||
#include <linux/if_xdp.h>
|
||||
#include <linux/if_link.h>
|
||||
#include <linux/if_xdp.h>
|
||||
|
||||
#include <bpf/bpf.h>
|
||||
#include <bpf/libbpf.h>
|
||||
|
||||
#define PROG_MAX 64
|
||||
struct xdp_ctx {
|
||||
char file[PATH_MAX];
|
||||
char progname[PROG_MAX];
|
||||
__u32 flags;
|
||||
char ifindex;
|
||||
struct bpf_object *obj;
|
||||
struct bpf_program *prog;
|
||||
int fd;
|
||||
};
|
||||
|
||||
struct xdp_map {
|
||||
char *net;
|
||||
char *prog;
|
||||
|
||||
char *map;
|
||||
int map_fd;
|
||||
int map_id;
|
||||
struct bpf_map_info map_info;
|
||||
struct bpf_map_info map_want;
|
||||
};
|
||||
|
||||
int xdp_load(struct xdp_ctx *ctx);
|
||||
int xdp_detach(struct xdp_ctx *ctx);
|
||||
|
||||
int map_verify(struct bpf_map_info *map, struct bpf_map_info *exp);
|
||||
int map_lookup(struct xdp_map *lookup);
|
||||
|
||||
void map_find(struct xdp_map *lookup, __u32 map);
|
||||
void prog_find(struct xdp_map *lookup, __u32 prog);
|
||||
void net_find(struct xdp_map *lookup);
|
||||
@@ -1,67 +0,0 @@
|
||||
#include "uxdp.h"
|
||||
|
||||
int
|
||||
xdp_load(struct xdp_ctx *ctx)
|
||||
{
|
||||
struct bpf_prog_load_attr attr = {
|
||||
.prog_type = BPF_PROG_TYPE_XDP,
|
||||
.file = ctx->file,
|
||||
};
|
||||
int err;
|
||||
int fd = -1;
|
||||
|
||||
err = bpf_prog_load_xattr(&attr, &ctx->obj, &fd);
|
||||
if (err) {
|
||||
fprintf(stderr, "failed to load %s %s\n", ctx->file, strerror(-err));
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->prog = bpf_object__find_program_by_title(ctx->obj, ctx->progname);
|
||||
if (!ctx->prog) {
|
||||
fprintf(stderr, "failed to find '%s'\n", ctx->progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->fd = bpf_program__fd(ctx->prog);
|
||||
if (ctx->fd <= 0) {
|
||||
fprintf(stderr, "failed to get fd %s\n", ctx->progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = bpf_set_link_xdp_fd(ctx->ifindex, ctx->fd, ctx->flags);
|
||||
if (err < 0) {
|
||||
switch(err) {
|
||||
case EBUSY:
|
||||
case EEXIST:
|
||||
fprintf(stderr, "program has already been loaded\n");
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "failed to load program\n");
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
xdp_detach(struct xdp_ctx *ctx)
|
||||
{
|
||||
__u32 id;
|
||||
|
||||
if (bpf_get_link_xdp_id(ctx->ifindex, &id, ctx->flags)) {
|
||||
fprintf(stderr, "xdp: failed to get link\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!id)
|
||||
return 0;
|
||||
|
||||
if (bpf_set_link_xdp_fd(ctx->ifindex, -1, ctx->flags)) {
|
||||
fprintf(stderr, "xdp: failed to detach\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "uxdp.h"
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
net_find(NULL);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#include "uxdp.h"
|
||||
|
||||
static int unload;
|
||||
|
||||
static void
|
||||
parse_cmdline(int argc, char **argv, struct xdp_ctx *ctx)
|
||||
{
|
||||
int ch;
|
||||
|
||||
while ((ch = getopt(argc, argv, "d:f:p:u")) != -1) {
|
||||
switch (ch) {
|
||||
case 'd':
|
||||
ctx->ifindex = if_nametoindex(optarg);
|
||||
break;
|
||||
case 'f':
|
||||
strncpy(ctx->file, optarg, sizeof(ctx->file));
|
||||
break;
|
||||
case 'p':
|
||||
strncpy(ctx->progname, optarg, sizeof(ctx->progname));
|
||||
break;
|
||||
case 'u':
|
||||
unload = 1;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Invalid argument\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct xdp_ctx ctx = {
|
||||
.flags = XDP_FLAGS_UPDATE_IF_NOEXIST | XDP_FLAGS_SKB_MODE,
|
||||
};
|
||||
|
||||
parse_cmdline(argc, argv, &ctx);
|
||||
|
||||
if (!ctx.ifindex) {
|
||||
fprintf(stderr, "invalid device\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (unload)
|
||||
return xdp_detach(&ctx);
|
||||
|
||||
if (!ctx.file[0] || !ctx.progname[0]) {
|
||||
fprintf(stderr, "invalid program\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return xdp_load(&ctx);
|
||||
}
|
||||
Reference in New Issue
Block a user