net/af_xdp: workaround custom program loading
authorCiara Loftus <ciara.loftus@intel.com>
Fri, 12 Nov 2021 10:30:02 +0000 (10:30 +0000)
committerFerruh Yigit <ferruh.yigit@intel.com>
Mon, 15 Nov 2021 17:01:09 +0000 (18:01 +0100)
Since v0.4.0, if the underlying kernel supports it, libbpf uses 'bpf
link' to manage the programs on the interfaces of the XDP sockets (xsks).
This is not compatible with the PMD's custom XDP program loading feature
which uses the netlink-based method for loading custom programs.

The conflict arises when libbpf searches for a custom program on the
interface using bpf link, but doesn't find one because the netlink
method was used. libbpf then proceeds to try to load the default program
on the interface, but fails due to the presence of the custom program.

To work around this, the PMD now uses the
XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD flag which prevents libbpf from
attempting to search for or load a program. One repercussion is that
DPDK must now insert the xsk into the xsks_map as this was previously
handled by libbpf during the routines for program loading/probing.

Ideally, the PMD would use bpf link to load the custom program, however
at present there is no convenient and reliable way of detecting whether
the underlying kernel supports bpf link. Perhaps this may become
available in a future libbpf release, at which point we can switch the
PMD over to the new bpf link based method.

Signed-off-by: Ciara Loftus <ciara.loftus@intel.com>
drivers/net/af_xdp/rte_eth_af_xdp.c

index 1c7689c..96c2c9d 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/ethtool.h>
 #include <linux/sockios.h>
 #include "af_xdp_deps.h"
+#include <bpf/bpf.h>
 #include <bpf/xsk.h>
 
 #include <rte_ethdev.h>
@@ -139,6 +140,7 @@ struct pmd_internals {
        bool shared_umem;
        char prog_path[PATH_MAX];
        bool custom_prog_configured;
+       struct bpf_map *map;
 
        struct rte_ether_addr eth_addr;
 
@@ -1147,11 +1149,10 @@ err:
 }
 
 static int
-load_custom_xdp_prog(const char *prog_path, int if_index)
+load_custom_xdp_prog(const char *prog_path, int if_index, struct bpf_map **map)
 {
        int ret, prog_fd = -1;
        struct bpf_object *obj;
-       struct bpf_map *map;
 
        ret = bpf_prog_load(prog_path, BPF_PROG_TYPE_XDP, &obj, &prog_fd);
        if (ret) {
@@ -1161,11 +1162,10 @@ load_custom_xdp_prog(const char *prog_path, int if_index)
 
        /*
         * The loaded program must provision for a map of xsks, such that some
-        * traffic can be redirected to userspace. When the xsk is created,
-        * libbpf inserts it into the map.
+        * traffic can be redirected to userspace.
         */
-       map = bpf_object__find_map_by_name(obj, "xsks_map");
-       if (!map) {
+       *map = bpf_object__find_map_by_name(obj, "xsks_map");
+       if (!*map) {
                AF_XDP_LOG(ERR, "Failed to find xsks_map in %s\n", prog_path);
                return -1;
        }
@@ -1272,13 +1272,15 @@ xsk_configure(struct pmd_internals *internals, struct pkt_rx_queue *rxq,
        if (strnlen(internals->prog_path, PATH_MAX) &&
                                !internals->custom_prog_configured) {
                ret = load_custom_xdp_prog(internals->prog_path,
-                                          internals->if_index);
+                                          internals->if_index,
+                                          &internals->map);
                if (ret) {
                        AF_XDP_LOG(ERR, "Failed to load custom XDP program %s\n",
                                        internals->prog_path);
                        goto err;
                }
                internals->custom_prog_configured = 1;
+               cfg.libbpf_flags = XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD;
        }
 
        if (internals->shared_umem)
@@ -1295,6 +1297,19 @@ xsk_configure(struct pmd_internals *internals, struct pkt_rx_queue *rxq,
                goto err;
        }
 
+       /* insert the xsk into the xsks_map */
+       if (internals->custom_prog_configured) {
+               int err, fd;
+
+               fd = xsk_socket__fd(rxq->xsk);
+               err = bpf_map_update_elem(bpf_map__fd(internals->map),
+                                         &rxq->xsk_queue_idx, &fd, 0);
+               if (err) {
+                       AF_XDP_LOG(ERR, "Failed to insert xsk in map.\n");
+                       goto err;
+               }
+       }
+
 #if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG)
        ret = rte_pktmbuf_alloc_bulk(rxq->umem->mb_pool, fq_bufs, reserve_size);
        if (ret) {