From: peltan Date: Mon, 6 Jan 2020 17:28:01 +0000 (+0100) Subject: xdp: load bpf program exactly once at knotd start X-Git-Tag: embedded_lmdb~35^2~74 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=66cbd962b6803f3f6ec2dcdc3d5b87d09653ab29;p=thirdparty%2Fknot-dns.git xdp: load bpf program exactly once at knotd start --- diff --git a/src/knot/server/server.c b/src/knot/server/server.c index 847dac4a2a..a121508d17 100644 --- a/src/knot/server/server.c +++ b/src/knot/server/server.c @@ -361,7 +361,7 @@ static iface_t *server_init_iface(struct sockaddr_storage *addr, } ret = knot_xsk_init(new_if->sock_xdp + i, dev, i, - sockaddr_port(addr)); + sockaddr_port(addr), i == 0); free(dev); if (ret != KNOT_EOK) { log_warning("failed to init XDP (%s)", knot_strerror(ret)); diff --git a/src/libknot/xdp/af_xdp.c b/src/libknot/xdp/af_xdp.c index d6d25f12f5..437349c30e 100644 --- a/src/libknot/xdp/af_xdp.c +++ b/src/libknot/xdp/af_xdp.c @@ -163,7 +163,7 @@ void knot_xsk_deinit(struct knot_xsk_socket *socket) xsk_socket__delete(socket->xsk); xsk_umem__delete(socket->umem->umem); - kxsk_iface_free((struct kxsk_iface *)/*const-cast*/socket->iface, true); + kxsk_iface_free((struct kxsk_iface *)/*const-cast*/socket->iface); free(socket); } @@ -599,13 +599,13 @@ void knot_xsk_free_recvd(struct knot_xsk_socket *socket, const knot_xsk_msg_t *m _public_ int knot_xsk_init(struct knot_xsk_socket **socket, const char *ifname, int if_queue, - int listen_port) + int listen_port, bool load_bpf) { if (socket == NULL || *socket != NULL) { return KNOT_EINVAL; } - struct kxsk_iface *iface = kxsk_iface_new(ifname); + struct kxsk_iface *iface = kxsk_iface_new(ifname, load_bpf); if (!iface) { return KNOT_EINVAL; } @@ -614,14 +614,14 @@ int knot_xsk_init(struct knot_xsk_socket **socket, const char *ifname, int if_qu struct xsk_umem_info *umem = configure_xsk_umem(&global_umem_config, UMEM_FRAME_COUNT); if (umem == NULL) { - kxsk_iface_free(iface, false); + kxsk_iface_free(iface); return KNOT_ENOMEM; } *socket = xsk_configure_socket(umem, iface, if_queue); if (!*socket) { xsk_umem__delete(umem->umem); - kxsk_iface_free(iface, false); + kxsk_iface_free(iface); return KNOT_NET_ESOCKET; } @@ -629,7 +629,7 @@ int knot_xsk_init(struct knot_xsk_socket **socket, const char *ifname, int if_qu if (ret != KNOT_EOK) { xsk_socket__delete((*socket)->xsk); xsk_umem__delete((*socket)->umem->umem); - kxsk_iface_free(iface, false); + kxsk_iface_free(iface); free(*socket); *socket = NULL; return ret; diff --git a/src/libknot/xdp/af_xdp.h b/src/libknot/xdp/af_xdp.h index 6a21380c48..c3b2fa171d 100644 --- a/src/libknot/xdp/af_xdp.h +++ b/src/libknot/xdp/af_xdp.h @@ -32,7 +32,7 @@ typedef struct { struct knot_xsk_socket; int knot_xsk_init(struct knot_xsk_socket **socket, const char *ifname, int if_queue, - int listen_port); + int listen_port, bool load_bpf); void knot_xsk_deinit(struct knot_xsk_socket *socket); diff --git a/src/libknot/xdp/bpf-user.c b/src/libknot/xdp/bpf-user.c index 520b1bd09a..902acc63a1 100644 --- a/src/libknot/xdp/bpf-user.c +++ b/src/libknot/xdp/bpf-user.c @@ -30,19 +30,10 @@ static int ensure_udp_prog(struct kxsk_iface *iface, const char *prog_fname) { - int ret; - - uint32_t prog_id; - ret = bpf_get_link_xdp_id(iface->ifindex, &prog_id, 0); - if (ret) - return -abs(ret); - if (prog_id) - return bpf_prog_get_fd_by_id(prog_id); - /* Use libbpf for extracting BPF byte-code from BPF-ELF object, and * loading this into the kernel via bpf-syscall */ int prog_fd; - ret = bpf_prog_load(prog_fname, BPF_PROG_TYPE_XDP, &iface->prog_obj, &prog_fd); + int ret = bpf_prog_load(prog_fname, BPF_PROG_TYPE_XDP, &iface->prog_obj, &prog_fd); if (ret) { fprintf(stderr, "[kxsk] failed loading BPF program (%s) (%d): %s\n", prog_fname, ret, strerror(-ret)); @@ -54,7 +45,7 @@ static int ensure_udp_prog(struct kxsk_iface *iface, const char *prog_fname) fprintf(stderr, "bpf_set_link_xdp_fd() == %d\n", ret); return -abs(ret); } else { - fprintf(stderr, "[kxsk] loaded BPF program\n"); + fprintf(stderr, "[kxsk] loaded BPF program %d %d\n", iface->ifindex, prog_fd); } return prog_fd; @@ -199,9 +190,9 @@ int kxsk_socket_stop(const struct kxsk_iface *iface, int queue_id) return err; } -struct kxsk_iface * kxsk_iface_new(const char *ifname) +struct kxsk_iface * kxsk_iface_new(const char *ifname, bool load_bpf) { - struct kxsk_iface *iface = malloc(sizeof(*iface)); + struct kxsk_iface *iface = calloc(1, sizeof(*iface)); if (!iface) { errno = ENOMEM; return NULL; @@ -214,7 +205,17 @@ struct kxsk_iface * kxsk_iface_new(const char *ifname) } iface->qidconf_map_fd = iface->xsks_map_fd = -1; - int ret = ensure_udp_prog_builtin(iface); + int ret; + if (load_bpf) { + ret = ensure_udp_prog_builtin(iface); + } else { + uint32_t prog_id = 0; + ret = bpf_get_link_xdp_id(iface->ifindex, &prog_id, 0); + if (!ret && prog_id) { + ret = bpf_prog_get_fd_by_id(prog_id); + } + } + if (ret >= 0) ret = get_bpf_maps(ret, iface); @@ -227,15 +228,14 @@ struct kxsk_iface * kxsk_iface_new(const char *ifname) iface->ifname = strdup(iface->ifname); return iface; } -void kxsk_iface_free(struct kxsk_iface *iface, bool unload_bpf) +void kxsk_iface_free(struct kxsk_iface *iface) { unget_bpf_maps(iface); - if (unload_bpf) { - int ret = bpf_set_link_xdp_fd(iface->ifindex, -1, 0); - printf("set link fd %d (%s) %d\n", ret, strerror(errno), iface->ifindex); + if (iface->prog_obj != NULL) { (void)bpf_object__close(iface->prog_obj); } + free((char *)/*const-cast*/iface->ifname); free(iface); } diff --git a/src/libknot/xdp/bpf-user.h b/src/libknot/xdp/bpf-user.h index da12f70236..5293462e9f 100644 --- a/src/libknot/xdp/bpf-user.h +++ b/src/libknot/xdp/bpf-user.h @@ -96,14 +96,14 @@ typedef struct knot_xsk_socket { * Note: if one is loaded on the interface already, we assume it's ours. * LATER: it might be possible to check, e.g. by naming our maps unusually. */ -struct kxsk_iface * kxsk_iface_new(const char *ifname); +struct kxsk_iface * kxsk_iface_new(const char *ifname, bool load_bpf); /** Undo kxsk_iface_new(). It's always freed, even if some problems happen. * * Unloading the BPF program is optional, as keeping it only adds some overhead, * and in case of multi-process it isn't easy to find that we're the last instance. */ -void kxsk_iface_free(struct kxsk_iface *iface, bool unload_bpf); +void kxsk_iface_free(struct kxsk_iface *iface); /** Activate this AF_XDP socket through the BPF maps. */ int kxsk_socket_start(const struct kxsk_iface *iface, int queue_id,