diff options
author | Anton Ivanov <anton.ivanov@cambridgegreys.com> | 2019-10-02 13:26:45 +0300 |
---|---|---|
committer | Richard Weinberger <richard@nod.at> | 2019-11-26 00:43:31 +0300 |
commit | 9807019a62dc670c73ce8e59e09b41ae458c34b3 (patch) | |
tree | 0ba729a1c5591cec5b6ad09117c0dac8f6abe1a6 /arch/um/drivers/vector_user.c | |
parent | 7d8093a56063e5d7c4459d9d025a57e0c5186ce9 (diff) | |
download | linux-9807019a62dc670c73ce8e59e09b41ae458c34b3.tar.xz |
um: Loadable BPF "Firmware" for vector drivers
All vector drivers now allow a BPF program to be loaded and
associated with the RX socket in the host kernel.
1. The program can be loaded as an extra kernel command line
option to any of the vector drivers.
2. The program can also be loaded as "firmware", using the
ethtool flash option. It is possible to turn this facility
on or off using a command line option.
A simplistic wrapper for generating the BPF firmware for the raw
socket driver out of a tcpdump/libpcap filter expression can be
found at: https://github.com/kot-begemot-uk/uml_vector_utilities/
Signed-off-by: Anton Ivanov <anton.ivanov@cambridgegreys.com>
Signed-off-by: Richard Weinberger <richard@nod.at>
Diffstat (limited to 'arch/um/drivers/vector_user.c')
-rw-r--r-- | arch/um/drivers/vector_user.c | 94 |
1 files changed, 76 insertions, 18 deletions
diff --git a/arch/um/drivers/vector_user.c b/arch/um/drivers/vector_user.c index e2c969b9f7ee..ddcd917be0af 100644 --- a/arch/um/drivers/vector_user.c +++ b/arch/um/drivers/vector_user.c @@ -46,7 +46,8 @@ #define TUN_GET_F_FAIL "tapraw: TUNGETFEATURES failed: %s" #define L2TPV3_BIND_FAIL "l2tpv3_open : could not bind socket err=%i" #define UNIX_BIND_FAIL "unix_open : could not bind socket err=%i" -#define BPF_ATTACH_FAIL "Failed to attach filter size %d to %d, err %d\n" +#define BPF_ATTACH_FAIL "Failed to attach filter size %d prog %px to %d, err %d\n" +#define BPF_DETACH_FAIL "Failed to detach filter size %d prog %px to %d, err %d\n" #define MAX_UN_LEN 107 @@ -660,31 +661,44 @@ int uml_vector_recvmmsg( else return -errno; } -int uml_vector_attach_bpf(int fd, void *bpf, int bpf_len) +int uml_vector_attach_bpf(int fd, void *bpf) { - int err = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, bpf, bpf_len); + struct sock_fprog *prog = bpf; + + int err = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, bpf, sizeof(struct sock_fprog)); if (err < 0) - printk(KERN_ERR BPF_ATTACH_FAIL, bpf_len, fd, -errno); + printk(KERN_ERR BPF_ATTACH_FAIL, prog->len, prog->filter, fd, -errno); return err; } -#define DEFAULT_BPF_LEN 6 +int uml_vector_detach_bpf(int fd, void *bpf) +{ + struct sock_fprog *prog = bpf; -void *uml_vector_default_bpf(int fd, void *mac) + int err = setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, bpf, sizeof(struct sock_fprog)); + if (err < 0) + printk(KERN_ERR BPF_DETACH_FAIL, prog->len, prog->filter, fd, -errno); + return err; +} +void *uml_vector_default_bpf(void *mac) { struct sock_filter *bpf; uint32_t *mac1 = (uint32_t *)(mac + 2); uint16_t *mac2 = (uint16_t *) mac; - struct sock_fprog bpf_prog = { - .len = 6, - .filter = NULL, - }; + struct sock_fprog *bpf_prog; + bpf_prog = uml_kmalloc(sizeof(struct sock_fprog), UM_GFP_KERNEL); + if (bpf_prog) { + bpf_prog->len = DEFAULT_BPF_LEN; + bpf_prog->filter = NULL; + } else { + return NULL; + } bpf = uml_kmalloc( sizeof(struct sock_filter) * DEFAULT_BPF_LEN, UM_GFP_KERNEL); - if (bpf != NULL) { - bpf_prog.filter = bpf; + if (bpf) { + bpf_prog->filter = bpf; /* ld [8] */ bpf[0] = (struct sock_filter){ 0x20, 0, 0, 0x00000008 }; /* jeq #0xMAC[2-6] jt 2 jf 5*/ @@ -697,12 +711,56 @@ void *uml_vector_default_bpf(int fd, void *mac) bpf[4] = (struct sock_filter){ 0x6, 0, 0, 0x00000000 }; /* ret #0x40000 */ bpf[5] = (struct sock_filter){ 0x6, 0, 0, 0x00040000 }; - if (uml_vector_attach_bpf( - fd, &bpf_prog, sizeof(struct sock_fprog)) < 0) { - kfree(bpf); - bpf = NULL; - } + } else { + kfree(bpf_prog); + bpf_prog = NULL; } - return bpf; + return bpf_prog; } +/* Note - this function requires a valid mac being passed as an arg */ + +void *uml_vector_user_bpf(char *filename) +{ + struct sock_filter *bpf; + struct sock_fprog *bpf_prog; + struct stat statbuf; + int res, ffd = -1; + + if (filename == NULL) + return NULL; + + if (stat(filename, &statbuf) < 0) { + printk(KERN_ERR "Error %d reading bpf file", -errno); + return false; + } + bpf_prog = uml_kmalloc(sizeof(struct sock_fprog), UM_GFP_KERNEL); + if (bpf_prog != NULL) { + bpf_prog->len = statbuf.st_size / sizeof(struct sock_filter); + bpf_prog->filter = NULL; + } + ffd = os_open_file(filename, of_read(OPENFLAGS()), 0); + if (ffd < 0) { + printk(KERN_ERR "Error %d opening bpf file", -errno); + goto bpf_failed; + } + bpf = uml_kmalloc(statbuf.st_size, UM_GFP_KERNEL); + if (bpf == NULL) { + printk(KERN_ERR "Failed to allocate bpf buffer"); + goto bpf_failed; + } + bpf_prog->filter = bpf; + res = os_read_file(ffd, bpf, statbuf.st_size); + if (res < statbuf.st_size) { + printk(KERN_ERR "Failed to read bpf program %s, error %d", filename, res); + kfree(bpf); + goto bpf_failed; + } + os_close_file(ffd); + return bpf_prog; +bpf_failed: + if (ffd > 0) + os_close_file(ffd); + kfree(bpf_prog); + return NULL; +} |