From 5c1f33e2a03c0b8710b5d910a46f1e1fb0607679 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 17 Sep 2019 13:20:14 +0200 Subject: um: Don't trace irqflags during shutdown In the main() code, we eventually enable signals just before exec() or exit(), in order to to not have signals pending and delivered *after* the exec(). I've observed SIGSEGV loops at this point, and the reason seems to be the irqflags tracing; this makes sense as the kernel is no longer really functional at this point. Since there's really no reason to use unblock_signals_trace() here (I had just done a global search & replace), use the plain unblock_signals() in this case to avoid going into the no longer functional kernel. Fixes: 0dafcbe128d2 ("um: Implement TRACE_IRQFLAGS_SUPPORT") Signed-off-by: Johannes Berg Signed-off-by: Richard Weinberger --- arch/um/os-Linux/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/um') diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c index 8014dfac644d..c8a42ecbd7a2 100644 --- a/arch/um/os-Linux/main.c +++ b/arch/um/os-Linux/main.c @@ -170,7 +170,7 @@ int __init main(int argc, char **argv, char **envp) * that they won't be delivered after the exec, when * they are definitely not expected. */ - unblock_signals_trace(); + unblock_signals(); os_info("\n"); /* Reboot */ -- cgit v1.2.3-59-g8ed1b From 04e5b1fb01834a602acaae2276b67a783a8c6159 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 18 Sep 2019 21:24:13 +0200 Subject: um: virtio: Remove device on disconnect If the connection drops, just remove the device, we don't try to recover from this right now. Signed-off-by: Johannes Berg Signed-off-by: Richard Weinberger --- arch/um/drivers/virtio_uml.c | 64 +++++++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 19 deletions(-) (limited to 'arch/um') diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c index fc8c52cff5aa..ca3067302c15 100644 --- a/arch/um/drivers/virtio_uml.c +++ b/arch/um/drivers/virtio_uml.c @@ -42,6 +42,13 @@ #define to_virtio_uml_device(_vdev) \ container_of(_vdev, struct virtio_uml_device, vdev) +struct virtio_uml_platform_data { + u32 virtio_device_id; + const char *socket_path; + struct work_struct conn_broken_wk; + struct platform_device *pdev; +}; + struct virtio_uml_device { struct virtio_device vdev; struct platform_device *pdev; @@ -50,6 +57,7 @@ struct virtio_uml_device { u64 features; u64 protocol_features; u8 status; + u8 registered:1; }; struct virtio_uml_vq_info { @@ -107,12 +115,21 @@ static int vhost_user_recv_header(int fd, struct vhost_user_msg *msg) return full_read(fd, msg, sizeof(msg->header)); } -static int vhost_user_recv(int fd, struct vhost_user_msg *msg, +static int vhost_user_recv(struct virtio_uml_device *vu_dev, + int fd, struct vhost_user_msg *msg, size_t max_payload_size) { size_t size; int rc = vhost_user_recv_header(fd, msg); + if (rc == -ECONNRESET && vu_dev->registered) { + struct virtio_uml_platform_data *pdata; + + pdata = vu_dev->pdev->dev.platform_data; + + virtio_break_device(&vu_dev->vdev); + schedule_work(&pdata->conn_broken_wk); + } if (rc) return rc; size = msg->header.size; @@ -125,7 +142,7 @@ static int vhost_user_recv_resp(struct virtio_uml_device *vu_dev, struct vhost_user_msg *msg, size_t max_payload_size) { - int rc = vhost_user_recv(vu_dev->sock, msg, max_payload_size); + int rc = vhost_user_recv(vu_dev, vu_dev->sock, msg, max_payload_size); if (rc) return rc; @@ -155,7 +172,7 @@ static int vhost_user_recv_req(struct virtio_uml_device *vu_dev, struct vhost_user_msg *msg, size_t max_payload_size) { - int rc = vhost_user_recv(vu_dev->req_fd, msg, max_payload_size); + int rc = vhost_user_recv(vu_dev, vu_dev->req_fd, msg, max_payload_size); if (rc) return rc; @@ -963,11 +980,6 @@ static void virtio_uml_release_dev(struct device *d) /* Platform device */ -struct virtio_uml_platform_data { - u32 virtio_device_id; - const char *socket_path; -}; - static int virtio_uml_probe(struct platform_device *pdev) { struct virtio_uml_platform_data *pdata = pdev->dev.platform_data; @@ -1005,6 +1017,7 @@ static int virtio_uml_probe(struct platform_device *pdev) rc = register_virtio_device(&vu_dev->vdev); if (rc) put_device(&vu_dev->vdev.dev); + vu_dev->registered = 1; return rc; error_init: @@ -1034,13 +1047,31 @@ static struct device vu_cmdline_parent = { static bool vu_cmdline_parent_registered; static int vu_cmdline_id; +static int vu_unregister_cmdline_device(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct virtio_uml_platform_data *pdata = pdev->dev.platform_data; + + kfree(pdata->socket_path); + platform_device_unregister(pdev); + return 0; +} + +static void vu_conn_broken(struct work_struct *wk) +{ + struct virtio_uml_platform_data *pdata; + + pdata = container_of(wk, struct virtio_uml_platform_data, conn_broken_wk); + vu_unregister_cmdline_device(&pdata->pdev->dev, NULL); +} + static int vu_cmdline_set(const char *device, const struct kernel_param *kp) { const char *ids = strchr(device, ':'); unsigned int virtio_device_id; int processed, consumed, err; char *socket_path; - struct virtio_uml_platform_data pdata; + struct virtio_uml_platform_data pdata, *ppdata; struct platform_device *pdev; if (!ids || ids == device) @@ -1079,6 +1110,11 @@ static int vu_cmdline_set(const char *device, const struct kernel_param *kp) err = PTR_ERR_OR_ZERO(pdev); if (err) goto free; + + ppdata = pdev->dev.platform_data; + ppdata->pdev = pdev; + INIT_WORK(&ppdata->conn_broken_wk, vu_conn_broken); + return 0; free: @@ -1121,16 +1157,6 @@ __uml_help(vu_cmdline_param_ops, ); -static int vu_unregister_cmdline_device(struct device *dev, void *data) -{ - struct platform_device *pdev = to_platform_device(dev); - struct virtio_uml_platform_data *pdata = pdev->dev.platform_data; - - kfree(pdata->socket_path); - platform_device_unregister(pdev); - return 0; -} - static void vu_unregister_cmdline_devices(void) { if (vu_cmdline_parent_registered) { -- cgit v1.2.3-59-g8ed1b From 7e60746005573a06149cdee7acedf428906f3a59 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 24 Sep 2019 09:21:17 +0200 Subject: um: virtio: Keep reading on -EAGAIN When we get an interrupt from the socket getting readable, and start reading, there's a possibility for a race. This depends on the implementation of the device, but e.g. with qemu's libvhost-user, we can see: device virtio_uml --------------------------------------- write header get interrupt read header read body -> returns -EAGAIN write body The -EAGAIN return is because the socket is non-blocking, and then this leads us to abandon this message. In fact, we've already read the header, so when the get another signal/interrupt for the body, we again read it as though it's a new message header, and also abandon it for the same reason (wrong size etc.) This essentially breaks things, and if that message was one that required a response, it leads to a deadlock as the device is waiting for the response but we'll never reply. Fix this by spinning on -EAGAIN as well when we read the message body. We need to handle -EAGAIN as "no message" while reading the header, since we share an interrupt. Note that this situation is highly unlikely to occur in normal usage, since there will be very few messages and only in the startup phase. With the inband call feature this does tend to happen (eventually) though. Signed-off-by: Johannes Berg Signed-off-by: Richard Weinberger --- arch/um/drivers/virtio_uml.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'arch/um') diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c index ca3067302c15..76b97c2de9a8 100644 --- a/arch/um/drivers/virtio_uml.c +++ b/arch/um/drivers/virtio_uml.c @@ -91,7 +91,7 @@ static int full_sendmsg_fds(int fd, const void *buf, unsigned int len, return 0; } -static int full_read(int fd, void *buf, int len) +static int full_read(int fd, void *buf, int len, bool abortable) { int rc; @@ -101,7 +101,7 @@ static int full_read(int fd, void *buf, int len) buf += rc; len -= rc; } - } while (len && (rc > 0 || rc == -EINTR)); + } while (len && (rc > 0 || rc == -EINTR || (!abortable && rc == -EAGAIN))); if (rc < 0) return rc; @@ -112,7 +112,7 @@ static int full_read(int fd, void *buf, int len) static int vhost_user_recv_header(int fd, struct vhost_user_msg *msg) { - return full_read(fd, msg, sizeof(msg->header)); + return full_read(fd, msg, sizeof(msg->header), true); } static int vhost_user_recv(struct virtio_uml_device *vu_dev, @@ -135,7 +135,7 @@ static int vhost_user_recv(struct virtio_uml_device *vu_dev, size = msg->header.size; if (size > max_payload_size) return -EPROTO; - return full_read(fd, &msg->payload, size); + return full_read(fd, &msg->payload, size, false); } static int vhost_user_recv_resp(struct virtio_uml_device *vu_dev, -- cgit v1.2.3-59-g8ed1b From bf9f80cf0ccab5f346f7d3cdc445da8fcfe6ce34 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 8 Oct 2019 17:43:21 +0200 Subject: um: virtio_uml: Disallow modular build This driver *can* be a module, but then its parameters (socket path) are untrusted data from inside the VM, and that isn't allowed. Allow the code to only be built-in to avoid that. Fixes: 5d38f324993f ("um: drivers: Add virtio vhost-user driver") Signed-off-by: Johannes Berg Acked-by: Anton Ivanov Signed-off-by: Richard Weinberger --- arch/um/drivers/Kconfig | 2 +- arch/um/drivers/virtio_uml.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/um') diff --git a/arch/um/drivers/Kconfig b/arch/um/drivers/Kconfig index fea5a0d522dc..388096fb45a2 100644 --- a/arch/um/drivers/Kconfig +++ b/arch/um/drivers/Kconfig @@ -337,7 +337,7 @@ config UML_NET_SLIRP endmenu config VIRTIO_UML - tristate "UML driver for virtio devices" + bool "UML driver for virtio devices" select VIRTIO help This driver provides support for virtio based paravirtual device diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c index 76b97c2de9a8..023ced2250ea 100644 --- a/arch/um/drivers/virtio_uml.c +++ b/arch/um/drivers/virtio_uml.c @@ -4,12 +4,12 @@ * * Copyright(c) 2019 Intel Corporation * - * This module allows virtio devices to be used over a vhost-user socket. + * This driver allows virtio devices to be used over a vhost-user socket. * * Guest devices can be instantiated by kernel module or command line * parameters. One device will be created for each parameter. Syntax: * - * [virtio_uml.]device=:[:] + * virtio_uml.device=:[:] * where: * := vhost-user socket path to connect * := virtio device id (as in virtio_ids.h) -- cgit v1.2.3-59-g8ed1b From 7d8093a56063e5d7c4459d9d025a57e0c5186ce9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 20 Nov 2019 21:36:54 +0800 Subject: um: Fix Kconfig indentation Adjust indentation from spaces to tab (+optional two spaces) as in coding style with command like: $ sed -e 's/^ /\t/' -i */Kconfig Signed-off-by: Krzysztof Kozlowski Acked-by: Anton Ivanov Signed-off-by: Richard Weinberger --- arch/um/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/um') diff --git a/arch/um/Kconfig b/arch/um/Kconfig index fec6b4ca2b6e..2a6d04fcb3e9 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -153,7 +153,7 @@ config KERNEL_STACK_ORDER It is possible to reduce the stack to 1 for 64BIT and 0 for 32BIT on older (pre-2017) CPUs. It is not recommended on newer CPUs due to the increase in the size of the state which needs to be saved when handling - signals. + signals. config MMAPPER tristate "iomem emulation driver" -- cgit v1.2.3-59-g8ed1b From 9807019a62dc670c73ce8e59e09b41ae458c34b3 Mon Sep 17 00:00:00 2001 From: Anton Ivanov Date: Wed, 2 Oct 2019 11:26:45 +0100 Subject: 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 Signed-off-by: Richard Weinberger --- arch/um/drivers/vector_kern.c | 113 ++++++++++++++++++++++++++++++++++++++---- arch/um/drivers/vector_kern.h | 8 ++- arch/um/drivers/vector_user.c | 94 ++++++++++++++++++++++++++++------- arch/um/drivers/vector_user.h | 8 ++- 4 files changed, 193 insertions(+), 30 deletions(-) (limited to 'arch/um') diff --git a/arch/um/drivers/vector_kern.c b/arch/um/drivers/vector_kern.c index 769ffbd9e9a6..92617e16829e 100644 --- a/arch/um/drivers/vector_kern.c +++ b/arch/um/drivers/vector_kern.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (C) 2017 - Cambridge Greys Limited + * Copyright (C) 2017 - 2019 Cambridge Greys Limited * Copyright (C) 2011 - 2014 Cisco Systems Inc * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and @@ -21,6 +21,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -128,6 +131,23 @@ static int get_mtu(struct arglist *def) return ETH_MAX_PACKET; } +static char *get_bpf_file(struct arglist *def) +{ + return uml_vector_fetch_arg(def, "bpffile"); +} + +static bool get_bpf_flash(struct arglist *def) +{ + char *allow = uml_vector_fetch_arg(def, "bpfflash"); + long result; + + if (allow != NULL) { + if (kstrtoul(allow, 10, &result) == 0) + return (allow > 0); + } + return false; +} + static int get_depth(struct arglist *def) { char *mtu = uml_vector_fetch_arg(def, "depth"); @@ -176,6 +196,7 @@ static int get_transport_options(struct arglist *def) int vec_rx = VECTOR_RX; int vec_tx = VECTOR_TX; long parsed; + int result = 0; if (vector != NULL) { if (kstrtoul(vector, 10, &parsed) == 0) { @@ -186,14 +207,16 @@ static int get_transport_options(struct arglist *def) } } + if (get_bpf_flash(def)) + result = VECTOR_BPF_FLASH; if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0) - return 0; + return result; if (strncmp(transport, TRANS_HYBRID, TRANS_HYBRID_LEN) == 0) - return (vec_rx | VECTOR_BPF); + return (result | vec_rx | VECTOR_BPF); if (strncmp(transport, TRANS_RAW, TRANS_RAW_LEN) == 0) - return (vec_rx | vec_tx | VECTOR_QDISC_BYPASS); - return (vec_rx | vec_tx); + return (result | vec_rx | vec_tx | VECTOR_QDISC_BYPASS); + return (result | vec_rx | vec_tx); } @@ -1139,6 +1162,8 @@ static int vector_net_close(struct net_device *dev) } tasklet_kill(&vp->tx_poll); if (vp->fds->rx_fd > 0) { + if (vp->bpf) + uml_vector_detach_bpf(vp->fds->rx_fd, vp->bpf); os_close_file(vp->fds->rx_fd); vp->fds->rx_fd = -1; } @@ -1146,7 +1171,10 @@ static int vector_net_close(struct net_device *dev) os_close_file(vp->fds->tx_fd); vp->fds->tx_fd = -1; } + if (vp->bpf != NULL) + kfree(vp->bpf->filter); kfree(vp->bpf); + vp->bpf = NULL; kfree(vp->fds->remote_addr); kfree(vp->transport_data); kfree(vp->header_rxbuffer); @@ -1181,6 +1209,7 @@ static void vector_reset_tx(struct work_struct *work) netif_start_queue(vp->dev); netif_wake_queue(vp->dev); } + static int vector_net_open(struct net_device *dev) { struct vector_private *vp = netdev_priv(dev); @@ -1196,6 +1225,8 @@ static int vector_net_open(struct net_device *dev) vp->opened = true; spin_unlock_irqrestore(&vp->lock, flags); + vp->bpf = uml_vector_user_bpf(get_bpf_file(vp->parsed)); + vp->fds = uml_vector_user_open(vp->unit, vp->parsed); if (vp->fds == NULL) @@ -1267,8 +1298,11 @@ static int vector_net_open(struct net_device *dev) if (!uml_raw_enable_qdisc_bypass(vp->fds->rx_fd)) vp->options |= VECTOR_BPF; } - if ((vp->options & VECTOR_BPF) != 0) - vp->bpf = uml_vector_default_bpf(vp->fds->rx_fd, dev->dev_addr); + if (((vp->options & VECTOR_BPF) != 0) && (vp->bpf == NULL)) + vp->bpf = uml_vector_default_bpf(dev->dev_addr); + + if (vp->bpf != NULL) + uml_vector_attach_bpf(vp->fds->rx_fd, vp->bpf); netif_start_queue(dev); @@ -1347,6 +1381,65 @@ static void vector_net_get_drvinfo(struct net_device *dev, strlcpy(info->version, DRIVER_VERSION, sizeof(info->version)); } +static int vector_net_load_bpf_flash(struct net_device *dev, + struct ethtool_flash *efl) +{ + struct vector_private *vp = netdev_priv(dev); + struct vector_device *vdevice; + const struct firmware *fw; + int result = 0; + + if (!(vp->options & VECTOR_BPF_FLASH)) { + netdev_err(dev, "loading firmware not permitted: %s\n", efl->data); + return -1; + } + + spin_lock(&vp->lock); + + if (vp->bpf != NULL) { + if (vp->opened) + uml_vector_detach_bpf(vp->fds->rx_fd, vp->bpf); + kfree(vp->bpf->filter); + vp->bpf->filter = NULL; + } else { + vp->bpf = kmalloc(sizeof(struct sock_fprog), GFP_KERNEL); + if (vp->bpf == NULL) { + netdev_err(dev, "failed to allocate memory for firmware\n"); + goto flash_fail; + } + } + + vdevice = find_device(vp->unit); + + if (request_firmware(&fw, efl->data, &vdevice->pdev.dev)) + goto flash_fail; + + vp->bpf->filter = kmemdup(fw->data, fw->size, GFP_KERNEL); + if (!vp->bpf->filter) + goto free_buffer; + + vp->bpf->len = fw->size / sizeof(struct sock_filter); + release_firmware(fw); + + if (vp->opened) + result = uml_vector_attach_bpf(vp->fds->rx_fd, vp->bpf); + + spin_unlock(&vp->lock); + + return result; + +free_buffer: + release_firmware(fw); + +flash_fail: + spin_unlock(&vp->lock); + if (vp->bpf != NULL) + kfree(vp->bpf->filter); + kfree(vp->bpf); + vp->bpf = NULL; + return -1; +} + static void vector_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { @@ -1424,6 +1517,7 @@ static const struct ethtool_ops vector_net_ethtool_ops = { .get_ethtool_stats = vector_get_ethtool_stats, .get_coalesce = vector_get_coalesce, .set_coalesce = vector_set_coalesce, + .flash_device = vector_net_load_bpf_flash, }; @@ -1528,8 +1622,9 @@ static void vector_eth_configure( .in_write_poll = false, .coalesce = 2, .req_size = get_req_size(def), - .in_error = false - }); + .in_error = false, + .bpf = NULL + }); dev->features = dev->hw_features = (NETIF_F_SG | NETIF_F_FRAGLIST); tasklet_init(&vp->tx_poll, vector_tx_poll, (unsigned long)vp); diff --git a/arch/um/drivers/vector_kern.h b/arch/um/drivers/vector_kern.h index 4d292e6c07af..d0159082faf0 100644 --- a/arch/um/drivers/vector_kern.h +++ b/arch/um/drivers/vector_kern.h @@ -29,10 +29,13 @@ #define VECTOR_TX (1 << 1) #define VECTOR_BPF (1 << 2) #define VECTOR_QDISC_BYPASS (1 << 3) +#define VECTOR_BPF_FLASH (1 << 4) #define ETH_MAX_PACKET 1500 #define ETH_HEADER_OTHER 32 /* just in case someone decides to go mad on QnQ */ +#define MAX_FILTER_PROG (2 << 16) + struct vector_queue { struct mmsghdr *mmsg_vector; void **skbuff_vector; @@ -118,10 +121,13 @@ struct vector_private { bool in_write_poll; bool in_error; + /* guest allowed to use ethtool flash to load bpf */ + bool bpf_via_flash; + /* ethtool stats */ struct vector_estats estats; - void *bpf; + struct sock_fprog *bpf; char user[0]; }; 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; +} diff --git a/arch/um/drivers/vector_user.h b/arch/um/drivers/vector_user.h index 649ec250268b..91f35b266aba 100644 --- a/arch/um/drivers/vector_user.h +++ b/arch/um/drivers/vector_user.h @@ -28,6 +28,8 @@ #define TRANS_BESS "bess" #define TRANS_BESS_LEN strlen(TRANS_BESS) +#define DEFAULT_BPF_LEN 6 + #ifndef IPPROTO_GRE #define IPPROTO_GRE 0x2F #endif @@ -95,8 +97,10 @@ extern int uml_vector_recvmmsg( unsigned int vlen, unsigned int flags ); -extern void *uml_vector_default_bpf(int fd, void *mac); -extern int uml_vector_attach_bpf(int fd, void *bpf, int bpf_len); +extern void *uml_vector_default_bpf(void *mac); +extern void *uml_vector_user_bpf(char *filename); +extern int uml_vector_attach_bpf(int fd, void *bpf); +extern int uml_vector_detach_bpf(int fd, void *bpf); extern bool uml_raw_enable_qdisc_bypass(int fd); extern bool uml_raw_enable_vnet_headers(int fd); extern bool uml_tap_enable_vnet_headers(int fd); -- cgit v1.2.3-59-g8ed1b