From: Marek Majtyka <marekx.majtyka@xxxxxxxxx> Update xdpsock sample so that it utilizes netlink ethtool interface to get available XDP/XSK modes. This allows to automatically choose the best available mode of operation, if these are not provided explicitly. Signed-off-by: Marek Majtyka <marekx.majtyka@xxxxxxxxx> --- samples/bpf/xdpsock_user.c | 117 ++++++++++++++++++++++++++++++++++--- 1 file changed, 108 insertions(+), 9 deletions(-) diff --git a/samples/bpf/xdpsock_user.c b/samples/bpf/xdpsock_user.c index 1149e94ca32f..780e5d1d73a0 100644 --- a/samples/bpf/xdpsock_user.c +++ b/samples/bpf/xdpsock_user.c @@ -53,6 +53,9 @@ #define DEBUG_HEXDUMP 0 +#define XDP_MODES (XDP_FLAGS_SKB_MODE | XDP_FLAGS_DRV_MODE) +#define XSK_MODES (XDP_COPY | XDP_ZEROCOPY) + typedef __u64 u64; typedef __u32 u32; typedef __u16 u16; @@ -86,7 +89,7 @@ static u32 irq_no; static int irqs_at_init = -1; static int opt_poll; static int opt_interval = 1; -static u32 opt_xdp_bind_flags = XDP_USE_NEED_WAKEUP; +static u16 opt_xdp_bind_flags = XDP_USE_NEED_WAKEUP; static u32 opt_umem_flags; static int opt_unaligned_chunks; static int opt_mmap_flags; @@ -95,6 +98,8 @@ static int opt_timeout = 1000; static bool opt_need_wakeup = true; static u32 opt_num_xsks = 1; static u32 prog_id; +static u32 xdp_caps; +static u16 bind_caps; struct xsk_ring_stats { unsigned long rx_npkts; @@ -957,6 +962,26 @@ static void usage(const char *prog) exit(EXIT_FAILURE); } +static inline void set_drv_mode(void) +{ + opt_xdp_flags |= XDP_FLAGS_DRV_MODE; +} + +static inline void set_skb_mode(void) +{ + opt_xdp_flags |= XDP_FLAGS_SKB_MODE; +} + +static inline void set_zc_mode(void) +{ + opt_xdp_bind_flags |= XDP_ZEROCOPY; +} + +static inline void set_copy_mode(void) +{ + opt_xdp_bind_flags |= XDP_COPY; +} + static void parse_command_line(int argc, char **argv) { int option_index, c; @@ -989,20 +1014,19 @@ static void parse_command_line(int argc, char **argv) opt_poll = 1; break; case 'S': - opt_xdp_flags |= XDP_FLAGS_SKB_MODE; - opt_xdp_bind_flags |= XDP_COPY; + set_skb_mode(); break; case 'N': - /* default, set below */ + set_drv_mode(); break; case 'n': opt_interval = atoi(optarg); break; case 'z': - opt_xdp_bind_flags |= XDP_ZEROCOPY; + set_zc_mode(); break; case 'c': - opt_xdp_bind_flags |= XDP_COPY; + set_copy_mode(); break; case 'u': opt_umem_flags |= XDP_UMEM_UNALIGNED_CHUNK_FLAG; @@ -1069,9 +1093,6 @@ static void parse_command_line(int argc, char **argv) } } - if (!(opt_xdp_flags & XDP_FLAGS_SKB_MODE)) - opt_xdp_flags |= XDP_FLAGS_DRV_MODE; - opt_ifindex = if_nametoindex(opt_if); if (!opt_ifindex) { fprintf(stderr, "ERROR: interface \"%s\" does not exist\n", @@ -1461,6 +1482,76 @@ static void enter_xsks_into_map(struct bpf_object *obj) } } +static inline u32 xdp_mode_not_set(void) +{ + return (opt_xdp_flags & XDP_MODES) == 0; +} + +static inline u16 bind_mode_not_set(void) +{ + return (opt_xdp_bind_flags & XSK_MODES) == 0; +} + +static inline u16 zc_mode_set(void) +{ + return opt_xdp_bind_flags & XDP_ZEROCOPY; +} + +static inline u32 drv_mode_set(void) +{ + return opt_xdp_flags & XDP_FLAGS_DRV_MODE; +} + +static inline u16 zc_mode_available(void) +{ + return bind_caps & XDP_ZEROCOPY; +} + +static inline u32 drv_mode_available(void) +{ + return xdp_caps & XDP_FLAGS_DRV_MODE; +} + +static void set_xsk_default_flags(void) +{ + if (drv_mode_available()) { + set_drv_mode(); + + if (zc_mode_available()) + set_zc_mode(); + else + set_copy_mode(); + } else { + set_skb_mode(); + set_copy_mode(); + } +} + +static void adjust_missing_flags(void) +{ + if (xdp_mode_not_set()) { + if (bind_mode_not_set()) { + set_xsk_default_flags(); + } else { + if (zc_mode_set()) { + set_drv_mode(); + } else { + if (drv_mode_available()) + set_drv_mode(); + else + set_skb_mode(); + } + } + } else { + if (bind_mode_not_set()) { + if (drv_mode_set() && zc_mode_available()) + set_zc_mode(); + else + set_copy_mode(); + } + } +} + int main(int argc, char **argv) { struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; @@ -1473,6 +1564,14 @@ int main(int argc, char **argv) parse_command_line(argc, argv); + ret = xsk_socket__get_caps(opt_if, &xdp_caps, &bind_caps); + if (ret) { + fprintf(stderr, "ERROR: xsk_socket__get_caps\n"); + exit(EXIT_FAILURE); + } + + adjust_missing_flags(); + if (setrlimit(RLIMIT_MEMLOCK, &r)) { fprintf(stderr, "ERROR: setrlimit(RLIMIT_MEMLOCK) \"%s\"\n", strerror(errno)); -- 2.20.1