Re: [PATCH bpf-next v9 21/23] samples/bpf: add new hid_mouse example

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Aug 24, 2022 at 3:42 PM Benjamin Tissoires
<benjamin.tissoires@xxxxxxxxxx> wrote:
>
> Everything should be available in the selftest part of the tree, but
> providing an example without uhid and hidraw will be more easy to
> follow for users.
>
> This example will probably ever only work on the Etekcity Scroll 6E
> because we need to adapt the various raw values to the actual device.
>
> On that device, the X and Y axis will be swapped and inverted, and on
> any other device, chances are high that the device will not work until
> Ctrl-C is hit.
>
> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@xxxxxxxxxx>
>
> ---


Sorry, I realized that there are two 21/23 and 22/23...
This one should be disregarded, as there are minor improvements in the
other 21/23 :(

The good ones are the 2 starting with "samples/bpf: HID:"

Cheers,
Benjamin


>
>
> changes in v9:
> - amended the usage part
>
> no changes in v8
>
> changes in v7:
> - remove unnecessary __must_check definition
>
> changes in v6:
> - clean up code by removing old comments
>
> changes in v5:
> - bring back same features than v3, with the new API
>
> changes in v4:
> - dropped the not-yet-implemented rdesc_fixup
> - use the new API
>
> changes in v3:
> - use the new hid_get_data API
> - add a comment for the report descriptor fixup to explain what is done
>
> changes in v2:
> - split the series by bpf/libbpf/hid/selftests and samples
>
> fix hid_mouse
> ---
>  samples/bpf/.gitignore      |   1 +
>  samples/bpf/Makefile        |  23 ++++++
>  samples/bpf/hid_mouse.bpf.c | 134 ++++++++++++++++++++++++++++++
>  samples/bpf/hid_mouse.c     | 161 ++++++++++++++++++++++++++++++++++++
>  4 files changed, 319 insertions(+)
>  create mode 100644 samples/bpf/hid_mouse.bpf.c
>  create mode 100644 samples/bpf/hid_mouse.c
>
> diff --git a/samples/bpf/.gitignore b/samples/bpf/.gitignore
> index 0e7bfdbff80a..65440bd618b2 100644
> --- a/samples/bpf/.gitignore
> +++ b/samples/bpf/.gitignore
> @@ -2,6 +2,7 @@
>  cpustat
>  fds_example
>  hbm
> +hid_mouse
>  ibumad
>  lathist
>  lwt_len_hist
> diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
> index 727da3c5879b..a965bbfaca47 100644
> --- a/samples/bpf/Makefile
> +++ b/samples/bpf/Makefile
> @@ -57,6 +57,8 @@ tprogs-y += xdp_redirect_map
>  tprogs-y += xdp_redirect
>  tprogs-y += xdp_monitor
>
> +tprogs-y += hid_mouse
> +
>  # Libbpf dependencies
>  LIBBPF_SRC = $(TOOLS_PATH)/lib/bpf
>  LIBBPF_OUTPUT = $(abspath $(BPF_SAMPLES_PATH))/libbpf
> @@ -119,6 +121,8 @@ xdp_redirect-objs := xdp_redirect_user.o $(XDP_SAMPLE)
>  xdp_monitor-objs := xdp_monitor_user.o $(XDP_SAMPLE)
>  xdp_router_ipv4-objs := xdp_router_ipv4_user.o $(XDP_SAMPLE)
>
> +hid_mouse-objs := hid_mouse.o
> +
>  # Tell kbuild to always build the programs
>  always-y := $(tprogs-y)
>  always-y += sockex1_kern.o
> @@ -338,6 +342,8 @@ $(obj)/hbm_out_kern.o: $(src)/hbm.h $(src)/hbm_kern.h
>  $(obj)/hbm.o: $(src)/hbm.h
>  $(obj)/hbm_edt_kern.o: $(src)/hbm.h $(src)/hbm_kern.h
>
> +$(obj)/hid_mouse.o: $(obj)/hid_mouse.skel.h
> +
>  # Override includes for xdp_sample_user.o because $(srctree)/usr/include in
>  # TPROGS_CFLAGS causes conflicts
>  XDP_SAMPLE_CFLAGS += -Wall -O2 \
> @@ -422,6 +428,23 @@ $(BPF_SKELS_LINKED): $(BPF_OBJS_LINKED) $(BPFTOOL)
>         @echo "  BPF GEN-SKEL" $(@:.skel.h=)
>         $(Q)$(BPFTOOL) gen skeleton $(@:.skel.h=.lbpf.o) name $(notdir $(@:.skel.h=)) > $@
>
> +# Generate BPF skeletons for non XDP progs
> +OTHER_BPF_SKELS := hid_mouse.skel.h
> +
> +hid_mouse.skel.h-deps := hid_mouse.bpf.o
> +
> +OTHER_BPF_SRCS_LINKED := $(patsubst %.skel.h,%.bpf.c, $(OTHER_BPF_SKELS))
> +OTHER_BPF_OBJS_LINKED := $(patsubst %.bpf.c,$(obj)/%.bpf.o, $(OTHER_BPF_SRCS_LINKED))
> +OTHER_BPF_SKELS_LINKED := $(addprefix $(obj)/,$(OTHER_BPF_SKELS))
> +
> +$(OTHER_BPF_SKELS_LINKED): $(OTHER_BPF_OBJS_LINKED) $(BPFTOOL)
> +       @echo "  BPF GEN-OBJ " $(@:.skel.h=)
> +       $(Q)$(BPFTOOL) gen object $(@:.skel.h=.lbpf.o) $(addprefix $(obj)/,$($(@F)-deps))
> +       @echo "  BPF GEN-SKEL" $(@:.skel.h=)
> +       $(Q)$(BPFTOOL) gen skeleton $(@:.skel.h=.lbpf.o) name $(notdir $(@:.skel.h=_lskel)) > $@
> +#      $(call msg,GEN-SKEL,$@)
> +#      $(Q)$(BPFTOOL) gen skeleton $< > $@
> +
>  # asm/sysreg.h - inline assembly used by it is incompatible with llvm.
>  # But, there is no easy way to fix it, so just exclude it since it is
>  # useless for BPF samples.
> diff --git a/samples/bpf/hid_mouse.bpf.c b/samples/bpf/hid_mouse.bpf.c
> new file mode 100644
> index 000000000000..0113e603f7a7
> --- /dev/null
> +++ b/samples/bpf/hid_mouse.bpf.c
> @@ -0,0 +1,134 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include "vmlinux.h"
> +#include <bpf/bpf_helpers.h>
> +#include <bpf/bpf_tracing.h>
> +
> +/* following are kfuncs exported by HID for HID-BPF */
> +extern int hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, u32 flags) __ksym;
> +extern __u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx,
> +                             unsigned int offset,
> +                             const size_t __sz) __ksym;
> +extern void hid_bpf_data_release(__u8 *data) __ksym;
> +extern int hid_bpf_hw_request(struct hid_bpf_ctx *ctx) __ksym;
> +
> +struct attach_prog_args {
> +       int prog_fd;
> +       unsigned int hid;
> +       int retval;
> +};
> +
> +SEC("syscall")
> +int attach_prog(struct attach_prog_args *ctx)
> +{
> +       ctx->retval = hid_bpf_attach_prog(ctx->hid,
> +                                         ctx->prog_fd,
> +                                         0);
> +       return 0;
> +}
> +
> +SEC("fmod_ret/hid_bpf_device_event")
> +int BPF_PROG(hid_y_event, struct hid_bpf_ctx *hctx)
> +{
> +       s16 y;
> +       __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 9 /* size */);
> +
> +       if (!data)
> +               return 0; /* EPERM check */
> +
> +       bpf_printk("event: size: %d", hctx->size);
> +       bpf_printk("incoming event: %02x %02x %02x",
> +                  data[0],
> +                  data[1],
> +                  data[2]);
> +       bpf_printk("                %02x %02x %02x",
> +                  data[3],
> +                  data[4],
> +                  data[5]);
> +       bpf_printk("                %02x %02x %02x",
> +                  data[6],
> +                  data[7],
> +                  data[8]);
> +
> +       y = data[3] | (data[4] << 8);
> +
> +       y = -y;
> +
> +       data[3] = y & 0xFF;
> +       data[4] = (y >> 8) & 0xFF;
> +
> +       bpf_printk("modified event: %02x %02x %02x",
> +                  data[0],
> +                  data[1],
> +                  data[2]);
> +       bpf_printk("                %02x %02x %02x",
> +                  data[3],
> +                  data[4],
> +                  data[5]);
> +       bpf_printk("                %02x %02x %02x",
> +                  data[6],
> +                  data[7],
> +                  data[8]);
> +
> +       return 0;
> +}
> +
> +SEC("fmod_ret/hid_bpf_device_event")
> +int BPF_PROG(hid_x_event, struct hid_bpf_ctx *hctx)
> +{
> +       s16 x;
> +       __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 9 /* size */);
> +
> +       if (!data)
> +               return 0; /* EPERM check */
> +
> +       x = data[1] | (data[2] << 8);
> +
> +       x = -x;
> +
> +       data[1] = x & 0xFF;
> +       data[2] = (x >> 8) & 0xFF;
> +       return 0;
> +}
> +
> +SEC("fmod_ret/hid_bpf_rdesc_fixup")
> +int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hctx)
> +{
> +       __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */);
> +
> +       if (!data)
> +               return 0; /* EPERM check */
> +
> +       bpf_printk("rdesc: %02x %02x %02x",
> +                  data[0],
> +                  data[1],
> +                  data[2]);
> +       bpf_printk("       %02x %02x %02x",
> +                  data[3],
> +                  data[4],
> +                  data[5]);
> +       bpf_printk("       %02x %02x %02x ...",
> +                  data[6],
> +                  data[7],
> +                  data[8]);
> +
> +       /*
> +        * The original report descriptor contains:
> +        *
> +        * 0x05, 0x01,                    //   Usage Page (Generic Desktop)      30
> +        * 0x16, 0x01, 0x80,              //   Logical Minimum (-32767)          32
> +        * 0x26, 0xff, 0x7f,              //   Logical Maximum (32767)           35
> +        * 0x09, 0x30,                    //   Usage (X)                         38
> +        * 0x09, 0x31,                    //   Usage (Y)                         40
> +        *
> +        * So byte 39 contains Usage X and byte 41 Usage Y.
> +        *
> +        * We simply swap the axes here.
> +        */
> +       data[39] = 0x31;
> +       data[41] = 0x30;
> +
> +       return 0;
> +}
> +
> +char _license[] SEC("license") = "GPL";
> diff --git a/samples/bpf/hid_mouse.c b/samples/bpf/hid_mouse.c
> new file mode 100644
> index 000000000000..bea3650787c5
> --- /dev/null
> +++ b/samples/bpf/hid_mouse.c
> @@ -0,0 +1,161 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/* Copyright (c) 2022 Benjamin Tissoires
> + *
> + * This is a pure HID-BPF example, and should be considered as such:
> + * on the Etekcity Scroll 6E, the X and Y axes will be swapped and
> + * inverted. On any other device... Not sure what this will do.
> + *
> + * This C main file is generic though. To adapt the code and test, users
> + * must amend only the .bpf.c file, which this program will load any
> + * eBPF program it finds.
> + */
> +
> +#include <assert.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <libgen.h>
> +#include <signal.h>
> +#include <stdbool.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <sys/resource.h>
> +#include <unistd.h>
> +
> +#include <linux/bpf.h>
> +#include <linux/errno.h>
> +
> +#include "bpf_util.h"
> +#include <bpf/bpf.h>
> +#include <bpf/libbpf.h>
> +
> +#include "hid_mouse.skel.h"
> +
> +static bool running = true;
> +
> +struct attach_prog_args {
> +       int prog_fd;
> +       unsigned int hid;
> +       int retval;
> +};
> +
> +static void int_exit(int sig)
> +{
> +       running = false;
> +       exit(0);
> +}
> +
> +static void usage(const char *prog)
> +{
> +       fprintf(stderr,
> +               "%s: %s /sys/bus/hid/devices/0BUS:0VID:0PID:00ID\n\n",
> +               __func__, prog);
> +       fprintf(stderr,
> +               "This program will upload and attach a HID-BPF program to the given device.\n"
> +               "On the Etekcity Scroll 6E, the X and Y axis will be inverted, but on any other\n"
> +               "device, chances are high that the device will not be working anymore\n\n"
> +               "consider this as a demo and adapt the eBPF program to your needs\n"
> +               "Hit Ctrl-C to unbind the program and reset the device\n");
> +}
> +
> +static int get_hid_id(const char *path)
> +{
> +       const char *str_id, *dir;
> +       char uevent[1024];
> +       int fd;
> +
> +       memset(uevent, 0, sizeof(uevent));
> +       snprintf(uevent, sizeof(uevent) - 1, "%s/uevent", path);
> +
> +       fd = open(uevent, O_RDONLY | O_NONBLOCK);
> +       if (fd < 0)
> +               return -ENOENT;
> +
> +       close(fd);
> +
> +       dir = basename((char *)path);
> +
> +       str_id = dir + sizeof("0003:0001:0A37.");
> +       return (int)strtol(str_id, NULL, 16);
> +}
> +
> +int main(int argc, char **argv)
> +{
> +       struct hid_mouse_lskel *skel;
> +       struct bpf_program *prog;
> +       int err;
> +       const char *optstr = "";
> +       const char *sysfs_path;
> +       int opt, hid_id, attach_fd;
> +       struct attach_prog_args args = {
> +               .retval = -1,
> +       };
> +       DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattr,
> +                           .ctx_in = &args,
> +                           .ctx_size_in = sizeof(args),
> +       );
> +
> +       while ((opt = getopt(argc, argv, optstr)) != -1) {
> +               switch (opt) {
> +               default:
> +                       usage(basename(argv[0]));
> +                       return 1;
> +               }
> +       }
> +
> +       if (optind == argc) {
> +               usage(basename(argv[0]));
> +               return 1;
> +       }
> +
> +       sysfs_path = argv[optind];
> +       if (!sysfs_path) {
> +               perror("sysfs");
> +               return 1;
> +       }
> +
> +       skel = hid_mouse_lskel__open_and_load();
> +       if (!skel) {
> +               fprintf(stderr, "%s  %s:%d", __func__, __FILE__, __LINE__);
> +               return -1;
> +       }
> +
> +       hid_id = get_hid_id(sysfs_path);
> +
> +       if (hid_id < 0) {
> +               fprintf(stderr, "can not open HID device: %m\n");
> +               return 1;
> +       }
> +       args.hid = hid_id;
> +
> +       attach_fd = bpf_program__fd(skel->progs.attach_prog);
> +       if (attach_fd < 0) {
> +               fprintf(stderr, "can't locate attach prog: %m\n");
> +               return 1;
> +       }
> +
> +       bpf_object__for_each_program(prog, *skel->skeleton->obj) {
> +               /* ignore syscalls */
> +               if (bpf_program__get_type(prog) != BPF_PROG_TYPE_TRACING)
> +                       continue;
> +
> +               args.retval = -1;
> +               args.prog_fd = bpf_program__fd(prog);
> +               err = bpf_prog_test_run_opts(attach_fd, &tattr);
> +               if (err) {
> +                       fprintf(stderr, "can't attach prog to hid device %d: %m (err: %d)\n",
> +                               hid_id, err);
> +                       return 1;
> +               }
> +       }
> +
> +       signal(SIGINT, int_exit);
> +       signal(SIGTERM, int_exit);
> +
> +       while (running)
> +               sleep(1);
> +
> +       hid_mouse_lskel__destroy(skel);
> +
> +       return 0;
> +}
> --
> 2.36.1
>




[Index of Archives]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Share Photos]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux