Skip to content
Snippets Groups Projects
Commit fa34a6b4 authored by Vladimír Čunát's avatar Vladimír Čunát Committed by Daniel Salzman
Browse files

xdp: add a third way of loading the BPF program

We need that in kresd, as overwriting the program would detach
all the AF_XDP sockets and only the last kresd could receive.
It's not perfect, but I suppose we can bear that extraneous message.
parent 70d38126
No related branches found
No related tags found
No related merge requests found
......@@ -236,7 +236,6 @@ static struct knot_xsk_socket *xsk_configure_socket(struct xsk_umem_info *umem,
.tx_size = XSK_RING_PROD__DEFAULT_NUM_DESCS,
.rx_size = XSK_RING_CONS__DEFAULT_NUM_DESCS,
.libbpf_flags = XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD,
.xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST,
};
errno = xsk_socket__create(&xsk_info->xsk, iface->ifname,
......@@ -600,7 +599,7 @@ 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, bool load_bpf)
int listen_port, knot_xsk_load_bpf_t load_bpf)
{
if (socket == NULL || *socket != NULL) {
return KNOT_EINVAL;
......
......@@ -30,6 +30,19 @@ typedef struct {
struct iovec payload;
} knot_xsk_msg_t;
/*! \brief Styles of loading BPF program.
*
* \note In *all* the cases loading can only succeed if at the end
* a compatible BPF program is loaded on the interface.
*/
typedef enum {
KNOT_XSK_LOAD_BPF_NEVER, /*!< Do not load; error out if not loaded already. */
KNOT_XSK_LOAD_BPF_ALWAYS, /*!< Always load a program (overwrite it). */
KNOT_XSK_LOAD_BPF_MAYBE, /*!< Try with present program or load if none. */
/* Implementation caveat: when re-using program in _MAYBE case, we get a message:
* libbpf: Kernel error message: XDP program already attached */
} knot_xsk_load_bpf_t;
/*! \brief Context structure for une XDP socket. */
struct knot_xsk_socket;
......@@ -45,7 +58,7 @@ struct knot_xsk_socket;
* \return KNOT_E*
*/
int knot_xsk_init(struct knot_xsk_socket **socket, const char *ifname, int if_queue,
int listen_port, bool load_bpf);
int listen_port, knot_xsk_load_bpf_t load_bpf);
/*! \brief De-init XDP socket. */
void knot_xsk_deinit(struct knot_xsk_socket *socket);
......
......@@ -26,9 +26,10 @@
#include <unistd.h>
#include <bpf/bpf.h>
#include <linux/if_link.h>
#include <net/if.h>
static int ensure_udp_prog(struct kxsk_iface *iface, const char *prog_fname)
static int ensure_udp_prog(struct kxsk_iface *iface, const char *prog_fname, bool overwrite)
{
/* Use libbpf for extracting BPF byte-code from BPF-ELF object, and
* loading this into the kernel via bpf-syscall */
......@@ -38,12 +39,23 @@ static int ensure_udp_prog(struct kxsk_iface *iface, const char *prog_fname)
return KNOT_EPROGRAM;
}
ret = bpf_set_link_xdp_fd(iface->ifindex, prog_fd, 0);
ret = bpf_set_link_xdp_fd(iface->ifindex, prog_fd,
overwrite ? 0 : XDP_FLAGS_UPDATE_IF_NOEXIST);
if (ret) {
close(prog_fd);
}
if (ret == -EBUSY && !overwrite) { /* We try accepting the present program. */
uint32_t prog_id = 0;
ret = bpf_get_link_xdp_id(iface->ifindex, &prog_id, 0);
if (!ret && prog_id) {
ret = prog_fd = bpf_prog_get_fd_by_id(prog_id);
}
}
if (ret < 0) {
return KNOT_EFD;
} else {
return prog_fd;
}
return prog_fd;
}
static int array2file(char *filename, const uint8_t *array, unsigned len)
......@@ -66,7 +78,7 @@ static int array2file(char *filename, const uint8_t *array, unsigned len)
return KNOT_EOK;
}
static int ensure_udp_prog_builtin(struct kxsk_iface *iface)
static int ensure_udp_prog_builtin(struct kxsk_iface *iface, bool overwrite)
{
if (bpf_kernel_o_len < 2) {
return KNOT_ENOTSUP;
......@@ -78,7 +90,7 @@ static int ensure_udp_prog_builtin(struct kxsk_iface *iface)
return ret;
}
ret = ensure_udp_prog(iface, filename);
ret = ensure_udp_prog(iface, filename, overwrite);
unlink(filename);
return ret;
}
......@@ -194,7 +206,8 @@ int kxsk_socket_stop(const struct kxsk_iface *iface, int queue_id)
return err;
}
int kxsk_iface_new(const char *ifname, bool load_bpf, struct kxsk_iface **out_iface)
int kxsk_iface_new(const char *ifname, knot_xsk_load_bpf_t load_bpf,
struct kxsk_iface **out_iface)
{
struct kxsk_iface *iface = calloc(1, sizeof(*iface));
if (iface == NULL) {
......@@ -209,14 +222,23 @@ int kxsk_iface_new(const char *ifname, bool load_bpf, struct kxsk_iface **out_if
iface->qidconf_map_fd = iface->xsks_map_fd = -1;
int ret;
if (load_bpf) {
ret = ensure_udp_prog_builtin(iface);
} else {
switch (load_bpf) {
case KNOT_XSK_LOAD_BPF_NEVER:
(void)0;
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);
}
break;
case KNOT_XSK_LOAD_BPF_ALWAYS:
ret = ensure_udp_prog_builtin(iface, true);
break;
case KNOT_XSK_LOAD_BPF_MAYBE:
ret = ensure_udp_prog_builtin(iface, false);
break;
default:
return KNOT_EINVAL;
}
if (ret >= 0) {
......
......@@ -16,7 +16,9 @@
#pragma once
#include <stdint.h>
#include <stdint.h>
#include "libknot/xdp/af_xdp.h"
#include <bpf/xsk.h>
......@@ -98,7 +100,8 @@ typedef struct knot_xsk_socket {
*
* \return KNOT_E*
*/
int kxsk_iface_new(const char *ifname, bool load_bpf, struct kxsk_iface **out_iface);
int kxsk_iface_new(const char *ifname, knot_xsk_load_bpf_t load_bpf,
struct kxsk_iface **out_iface);
/*!
* \brief Unload BPF maps for a socket.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment