#include <linux/ethtool.h>
#include <linux/if_link.h>
#include <linux/sockios.h>
-#include <bpf/libbpf.h>
+#include <linux/limits.h>
+#include <bpf/bpf.h>
#include <vlib/vlib.h>
#include <vlib/unix/unix.h>
#include <vlib/pci/pci.h>
#include <vnet/interface/tx_queue_funcs.h>
#include "af_xdp.h"
+#ifndef XDP_UMEM_MIN_CHUNK_SIZE
+#define XDP_UMEM_MIN_CHUNK_SIZE 2048
+#endif
+
af_xdp_main_t af_xdp_main;
typedef struct
return ret;
}
+static int
+af_xdp_remove_program (af_xdp_device_t *ad)
+{
+ u32 curr_prog_id = 0;
+ int ret;
+ int ns_fds[2];
+
+ af_xdp_enter_netns (ad->netns, ns_fds);
+ ret = bpf_xdp_query_id (ad->linux_ifindex, XDP_FLAGS_UPDATE_IF_NOEXIST,
+ &curr_prog_id);
+ if (ret != 0)
+ {
+ af_xdp_log (VLIB_LOG_LEVEL_ERR, ad, "bpf_xdp_query_id failed\n");
+ goto err0;
+ }
+
+ ret = bpf_xdp_detach (ad->linux_ifindex, XDP_FLAGS_UPDATE_IF_NOEXIST, NULL);
+ if (ret != 0)
+ {
+ af_xdp_log (VLIB_LOG_LEVEL_ERR, ad, "bpf_xdp_detach failed\n");
+ goto err0;
+ }
+ af_xdp_exit_netns (ad->netns, ns_fds);
+ if (ad->bpf_obj)
+ bpf_object__close (ad->bpf_obj);
+
+ return 0;
+
+err0:
+ af_xdp_exit_netns (ad->netns, ns_fds);
+ return ret;
+}
+
void
af_xdp_delete_if (vlib_main_t * vm, af_xdp_device_t * ad)
{
for (i = 0; i < ad->rxq_num; i++)
clib_file_del_by_index (&file_main, vec_elt (ad->rxqs, i).file_index);
- if (ad->bpf_obj)
- {
- int ns_fds[2];
- af_xdp_enter_netns (ad->netns, ns_fds);
- bpf_set_link_xdp_fd (ad->linux_ifindex, -1, 0);
- af_xdp_exit_netns (ad->netns, ns_fds);
-
- bpf_object__unload (ad->bpf_obj);
- }
+ if (af_xdp_remove_program (ad) != 0)
+ af_xdp_log (VLIB_LOG_LEVEL_ERR, ad, "Error while removing XDP program.\n");
vec_free (ad->xsk);
vec_free (ad->umem);
af_xdp_load_program (af_xdp_create_if_args_t * args, af_xdp_device_t * ad)
{
int fd;
+ struct bpf_program *bpf_prog;
+ struct rlimit r = { RLIM_INFINITY, RLIM_INFINITY };
- ad->linux_ifindex = if_nametoindex (ad->linux_ifname);
- if (!ad->linux_ifindex)
- {
- args->rv = VNET_API_ERROR_INVALID_VALUE;
- args->error =
- clib_error_return_unix (0, "if_nametoindex(%s) failed",
- ad->linux_ifname);
- goto err0;
- }
+ if (setrlimit (RLIMIT_MEMLOCK, &r))
+ af_xdp_log (VLIB_LOG_LEVEL_WARNING, ad,
+ "setrlimit(%s) failed: %s (errno %d)", ad->linux_ifname,
+ strerror (errno), errno);
- if (bpf_prog_load (args->prog, BPF_PROG_TYPE_XDP, &ad->bpf_obj, &fd))
+ ad->bpf_obj = bpf_object__open_file (args->prog, NULL);
+ if (libbpf_get_error (ad->bpf_obj))
{
args->rv = VNET_API_ERROR_SYSCALL_ERROR_5;
- args->error =
- clib_error_return_unix (0, "bpf_prog_load(%s) failed", args->prog);
+ args->error = clib_error_return_unix (
+ 0, "bpf_object__open_file(%s) failed", args->prog);
goto err0;
}
-#ifndef XDP_FLAGS_REPLACE
-#define XDP_FLAGS_REPLACE 0
-#endif
- if (bpf_set_link_xdp_fd (ad->linux_ifindex, fd, XDP_FLAGS_REPLACE))
+ bpf_prog = bpf_object__next_program (ad->bpf_obj, NULL);
+ if (!bpf_prog)
+ goto err1;
+
+ bpf_program__set_type (bpf_prog, BPF_PROG_TYPE_XDP);
+
+ if (bpf_object__load (ad->bpf_obj))
+ goto err1;
+
+ fd = bpf_program__fd (bpf_prog);
+
+ if (bpf_xdp_attach (ad->linux_ifindex, fd, XDP_FLAGS_UPDATE_IF_NOEXIST,
+ NULL))
{
args->rv = VNET_API_ERROR_SYSCALL_ERROR_6;
- args->error =
- clib_error_return_unix (0, "bpf_set_link_xdp_fd(%s) failed",
- ad->linux_ifname);
+ args->error = clib_error_return_unix (0, "bpf_xdp_attach(%s) failed",
+ ad->linux_ifname);
goto err1;
}
return 0;
err1:
- bpf_object__unload (ad->bpf_obj);
+ bpf_object__close (ad->bpf_obj);
ad->bpf_obj = 0;
err0:
- ad->linux_ifindex = ~0;
return -1;
}
(umem, uword_to_pointer (vm->buffer_main->buffer_mem_start, void *),
vm->buffer_main->buffer_mem_size, fq, cq, &umem_config))
{
+ uword sys_page_size = clib_mem_get_page_size ();
args->rv = VNET_API_ERROR_SYSCALL_ERROR_1;
args->error = clib_error_return_unix (0, "xsk_umem__create() failed");
+ /* this should mimic the Linux kernel net/xdp/xdp_umem.c:xdp_umem_reg()
+ * check */
+ if (umem_config.frame_size < XDP_UMEM_MIN_CHUNK_SIZE ||
+ umem_config.frame_size > sys_page_size)
+ args->error = clib_error_return (
+ args->error,
+ "(unsupported data-size? (should be between %d and %d))",
+ XDP_UMEM_MIN_CHUNK_SIZE - sizeof (vlib_buffer_t),
+ sys_page_size - sizeof (vlib_buffer_t));
goto err0;
}
sock_config.bind_flags |= XDP_ZEROCOPY;
break;
}
+ if (args->prog)
+ sock_config.libbpf_flags = XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD;
if (xsk_socket__create
(xsk, ad->linux_ifname, qid, *umem, rx, tx, &sock_config))
{
}
fd = xsk_socket__fd (*xsk);
+ if (args->prog)
+ {
+ struct bpf_map *map =
+ bpf_object__find_map_by_name (ad->bpf_obj, "xsks_map");
+ int ret = xsk_socket__update_xskmap (*xsk, bpf_map__fd (map));
+ if (ret)
+ {
+ args->rv = VNET_API_ERROR_SYSCALL_ERROR_3;
+ args->error = clib_error_return_unix (
+ 0, "xsk_socket__update_xskmap %s qid %d return %d",
+ ad->linux_ifname, qid, ret);
+ goto err2;
+ }
+ }
optlen = sizeof (opt);
+#ifndef SOL_XDP
+#define SOL_XDP 283
+#endif
if (getsockopt (fd, SOL_XDP, XDP_OPTIONS, &opt, &optlen))
{
- args->rv = VNET_API_ERROR_SYSCALL_ERROR_3;
+ args->rv = VNET_API_ERROR_SYSCALL_ERROR_4;
args->error =
clib_error_return_unix (0, "getsockopt(XDP_OPTIONS) failed");
goto err2;
ad->linux_ifname = (char *) format (0, "%s", args->linux_ifname);
vec_validate (ad->linux_ifname, IFNAMSIZ - 1); /* libbpf expects ifname to be at least IFNAMSIZ */
- ad->netns = (char *) format (0, "%s", args->netns);
+ if (args->netns)
+ ad->netns = (char *) format (0, "%s%c", args->netns, 0);
+
+ ad->linux_ifindex = if_nametoindex (ad->linux_ifname);
+ if (!ad->linux_ifindex)
+ {
+ args->rv = VNET_API_ERROR_INVALID_VALUE;
+ args->error = clib_error_return_unix (0, "if_nametoindex(%s) failed",
+ ad->linux_ifname);
+ ad->linux_ifindex = ~0;
+ goto err1;
+ }
- if (args->prog && af_xdp_load_program (args, ad))
+ if (args->prog &&
+ (af_xdp_remove_program (ad) || af_xdp_load_program (args, ad)))
goto err2;
q_num = clib_max (rxq_num, txq_num);
clib_error_free (ad->error);
}
-/* *INDENT-OFF* */
VNET_DEVICE_CLASS (af_xdp_device_class) = {
.name = "AF_XDP interface",
.format_device = format_af_xdp_device,
.mac_addr_change_function = af_xdp_mac_change,
.clear_counters = af_xdp_clear,
};
-/* *INDENT-ON* */
clib_error_t *
af_xdp_init (vlib_main_t * vm)