* Re: [PATCH 1/3] macvlan: Reflect macvlan packets meant for other macvlan devices
From: Eric Dumazet @ 2009-11-18 6:30 UTC (permalink / raw)
To: Arnd Bergmann
Cc: linux-kernel, netdev, David Miller, Stephen Hemminger, Herbert Xu,
Patrick McHardy, Patrick Mullaney, Eric W. Biederman,
Edge Virtual Bridging, Anna Fischer, bridge, virtualization,
Jens Osterkamp, Gerhard Stenzel
In-Reply-To: <1258497551-25959-2-git-send-email-arnd@arndb.de>
Arnd Bergmann a écrit :
> From: Eric Biederman <ebiederm@xmission.com>
>
> Switch ports do not send packets back out the same port they came
> in on. This causes problems when using a macvlan device inside
> of a network namespace as it becomes impossible to talk to
> other macvlan devices.
This patch is very welcome. I review it and found one oddity.
>
> Signed-off-by: Eric Biederman <ebiederm@xmission.com>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> +static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
> +{
> + const struct macvlan_dev *vlan = netdev_priv(dev);
> + const struct macvlan_port *port = vlan->port;
> + const struct macvlan_dev *dest;
> + const struct ethhdr *eth;
>
> - skb->dev = dev;
> - skb->pkt_type = PACKET_HOST;
> + skb->protocol = eth_type_trans(skb, dev);
> + eth = eth_hdr(skb);
>
> - netif_rx(skb);
> - return NULL;
> + skb_dst_drop(skb);
Why do you drop dst here ?
It seems strange, since this driver specifically masks out IFF_XMIT_DST_RELEASE
in its macvlan_setup() :
dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
If we really want to drop dst, it could be done by caller, if IFF_XMIT_DST_RELEASE
was not masked in macvlan_setup().
> + skb->mark = 0;
> + secpath_reset(skb);
> + nf_reset(skb);
> +
> + if (is_multicast_ether_addr(eth->h_dest)) {
> + macvlan_broadcast(skb, port, dev);
> + return macvlan_xmit_world(skb, dev);
> + }
> +
> + dest = macvlan_hash_lookup(port, eth->h_dest);
> + if (dest)
> + return macvlan_unicast(skb, dest);
> +
> + return macvlan_xmit_world(skb, dev);
> }
# find net drivers/net|xargs grep -n IFF_XMIT_DST_RELEASE
net/8021q/vlan_dev.c:837: dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
net/atm/clip.c:561: dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
net/core/dev.c:1778: if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
net/core/dev.c:5287: dev->priv_flags = IFF_XMIT_DST_RELEASE;
net/ipv4/ip_gre.c:1236: dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
net/ipv4/ipip.c:717: dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
net/ipv6/sit.c:1104: dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
drivers/net/appletalk/ipddp.c:76: dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
drivers/net/bonding/bond_main.c:4534: bond_dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
drivers/net/eql.c:197: dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
drivers/net/ifb.c:162: dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
drivers/net/loopback.c:174: dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
drivers/net/macvlan.c:421: dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
drivers/net/ppp_generic.c:1057: dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
drivers/net/wan/hdlc_fr.c:1057: dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
^ permalink raw reply
* Re: [PATCH] Documentation, clarify tuntap IPX example.
From: Max Krasnyansky @ 2009-11-18 5:52 UTC (permalink / raw)
To: andrew hendry; +Cc: netdev@vger.kernel.org, linux-kernel
In-Reply-To: <d45a3acc0911171814i310bbd16t8ff3fba2410e9375@mail.gmail.com>
andrew hendry wrote:
> Hi Max,
>
> I started looking through the documentation because im looking to use
> tun for X.25 over TCP. The IPX example sounded similar but i couldn't
> get it to work as I was expecting. Looking for a hint in the right
> direction.
Ah, X25 is different.
> There is an old non-mainline patch called x25tap (clone of obsolete
> ethertap). I'm hoping to replace x25tap with tun.
>
> The old x25tap creates a device like:
> x25tap0 Link encap:generic X.25 HWaddr
> UP BROADCAST RUNNING NOARP MULTICAST MTU:1024 Metric:1
> RX packets:3040785 errors:0 dropped:0 overruns:0 frame:0
> TX packets:2895530 errors:0 dropped:0 overruns:0 carrier:0
> collisions:0 txqueuelen:10
> RX bytes:138787339 (132.3 Mb) TX bytes:91395983 (87.1 Mb)
> When the x25tap is loaded it has dev->type = ARPHRD_X25, after which
> x.25 routing and AF_X25 sockets can be created. Along with an XoT
> userspace program which handles some basic headers and TCP port 1998
> it works well.
>
> If using tun, how does something get registered to handle protocol AF_X25?
>
I've never tried this personally so ... :). But I just glanced over net/ax25
and drivers/wan/ax25 and it looks TUNSETLINK might work for you.
In other words you want to allocate TUN device (not TAP) and then call
TUNSETLINK with ARPHRD_X25. Seems like you'll get exactly what you need.
Max
> Regards,
> Andrew.
>
> On Wed, Nov 18, 2009 at 12:40 PM, Max Krasnyansky <maxk@qualcomm.com> wrote:
>> On 11/17/2009 05:30 PM, andrew hendry wrote:
>>> Can the TUNSETIFF ioctl change a tap's protocol to IPX as the
>>> documentation suggests?
>>> I think tun.c would need IFF_IPX_TAP added for it to work as described?
>>> Otherwise tap can only be ptp or ethernet, and there is no way to
>>> route or use AF_IPX.
>> TAP is an Ethernet device. No special handling is required for IPX or for
>> that matter any other protocol. Example seems fine too.
>>
>> Max
>>
>>> Signed-off-by: Andrew Hendry<andrew.hendry@gmail.com>
>>>
>>> --- a/Documentation/networking/tuntap.txt 2009-11-11
>>> 14:03:22.676167648 +1100
>>> +++ b/Documentation/networking/tuntap.txt 2009-11-18
>>> 11:34:18.106647029 +1100
>>> @@ -127,12 +127,14 @@ Ethernet device, which instead of receiv
>>> media, receives them from user space program and instead of sending
>>> packets via physical media sends them to the user space program.
>>>
>>> -Let's say that you configured IPX on the tap0, then whenever
>>> -the kernel sends an IPX packet to tap0, it is passed to the application
>>> -(VTun for example). The application encrypts, compresses and sends it to
>>> -the other side over TCP or UDP. The application on the other side
>>> decompresses
>>> -and decrypts the data received and writes the packet to the TAP device,
>>> -the kernel handles the packet like it came from real physical device.
>>> +Let's say for the purpose of example, IPX support was added to tuntap.
>>> +Then whenever the kernel routes an IPX packet to tap0, it is passed to
>>> the
>>> +application reading the file descriptor from /dev/net/tun (VTun for
>>> example).
>>> +The application encrypts, compresses and sends it to the other side over
>>> TCP
>>> +or UDP. The application on the other side decompresses and decrypts the
>>> data
>>> +received and writes the packet to the TAP device, the remote kernel
>>> handles
>>> +the packet like it came from real physical device. The IPX applications
>>> are
>>> +able to communicate as if there was a real IPX network.
>>>
>>> 4. What is the difference between TUN driver and TAP driver?
>>> TUN works with IP frames. TAP works with Ethernet frames.
>>
^ permalink raw reply
* RE: [PATCHv9 3/3] vhost_net: a kernel-level virtio server
From: Xin, Xiaohui @ 2009-11-18 5:42 UTC (permalink / raw)
To: Michael S. Tsirkin, netdev@vger.kernel.org,
virtualization@lists.linux-foundation.org, "kvm@
In-Reply-To: <20091109172230.GD4724@redhat.com>
Michael,
>From the http://www.linux-kvm.org/page/VhostNet, we can see netperf with TCP_STREAM can get more than 4GMb/s for the receive side, and more than 5GMb/s for the send side.
Is it the result from the raw socket or through tap?
I want to duplicate such performance with vhost on my side. I can only get more than 1GMb/s with following conditions:
1) disabled the GRO feature in the host 10G NIC driver
2) vi->big_packet in guest is false
3) MTU is 1500.
4) raw socket, not the tap
5) using your vhost git tree
Is that the reasonable result with such conditions or maybe I have made some silly mistakes somewhere I don't know yet?
May you kindly describe your test environment/conditions in detail to have much better performance in your website (I really need the performance)?
And I have tested the tun support with vhost now, and may you share your /home/mst/ifup script here?
Thanks
Xiaohui
-----Original Message-----
From: kvm-owner@vger.kernel.org [mailto:kvm-owner@vger.kernel.org] On Behalf Of Michael S. Tsirkin
Sent: Tuesday, November 10, 2009 1:23 AM
To: netdev@vger.kernel.org; virtualization@lists.linux-foundation.org; kvm@vger.kernel.org; linux-kernel@vger.kernel.org; mingo@elte.hu; linux-mm@kvack.org; akpm@linux-foundation.org; hpa@zytor.com; gregory.haskins@gmail.com; Rusty Russell; s.hetze@linux-ag.com; Daniel Walker; Eric Dumazet
Subject: [PATCHv9 3/3] vhost_net: a kernel-level virtio server
What it is: vhost net is a character device that can be used to reduce
the number of system calls involved in virtio networking.
Existing virtio net code is used in the guest without modification.
There's similarity with vringfd, with some differences and reduced scope
- uses eventfd for signalling
- structures can be moved around in memory at any time (good for
migration, bug work-arounds in userspace)
- write logging is supported (good for migration)
- support memory table and not just an offset (needed for kvm)
common virtio related code has been put in a separate file vhost.c and
can be made into a separate module if/when more backends appear. I used
Rusty's lguest.c as the source for developing this part : this supplied
me with witty comments I wouldn't be able to write myself.
What it is not: vhost net is not a bus, and not a generic new system
call. No assumptions are made on how guest performs hypercalls.
Userspace hypervisors are supported as well as kvm.
How it works: Basically, we connect virtio frontend (configured by
userspace) to a backend. The backend could be a network device, or a tap
device. Backend is also configured by userspace, including vlan/mac
etc.
Status: This works for me, and I haven't see any crashes.
Compared to userspace, people reported improved latency (as I save up to
4 system calls per packet), as well as better bandwidth and CPU
utilization.
Features that I plan to look at in the future:
- mergeable buffers
- zero copy
- scalability tuning: figure out the best threading model to use
Note on RCU usage (this is also documented in vhost.h, near
private_pointer which is the value protected by this variant of RCU):
what is happening is that the rcu_dereference() is being used in a
workqueue item. The role of rcu_read_lock() is taken on by the start of
execution of the workqueue item, of rcu_read_unlock() by the end of
execution of the workqueue item, and of synchronize_rcu() by
flush_workqueue()/flush_work(). In the future we might need to apply
some gcc attribute or sparse annotation to the function passed to
INIT_WORK(). Paul's ack below is for this RCU usage.
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
MAINTAINERS | 9 +
arch/x86/kvm/Kconfig | 1 +
drivers/Makefile | 1 +
drivers/vhost/Kconfig | 11 +
drivers/vhost/Makefile | 2 +
drivers/vhost/net.c | 648 +++++++++++++++++++++++++++++
drivers/vhost/vhost.c | 965 ++++++++++++++++++++++++++++++++++++++++++++
drivers/vhost/vhost.h | 159 ++++++++
include/linux/Kbuild | 1 +
include/linux/miscdevice.h | 1 +
include/linux/vhost.h | 130 ++++++
11 files changed, 1928 insertions(+), 0 deletions(-)
create mode 100644 drivers/vhost/Kconfig
create mode 100644 drivers/vhost/Makefile
create mode 100644 drivers/vhost/net.c
create mode 100644 drivers/vhost/vhost.c
create mode 100644 drivers/vhost/vhost.h
create mode 100644 include/linux/vhost.h
diff --git a/MAINTAINERS b/MAINTAINERS
index a1a2ace..7d4bfa2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5636,6 +5636,15 @@ S: Maintained
F: Documentation/filesystems/vfat.txt
F: fs/fat/
+VIRTIO HOST (VHOST)
+M: "Michael S. Tsirkin" <mst@redhat.com>
+L: kvm@vger.kernel.org
+L: virtualization@lists.osdl.org
+L: netdev@vger.kernel.org
+S: Maintained
+F: drivers/vhost/
+F: include/linux/vhost.h
+
VIA RHINE NETWORK DRIVER
M: Roger Luethi <rl@hellgate.ch>
S: Maintained
diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig
index b84e571..94f44d9 100644
--- a/arch/x86/kvm/Kconfig
+++ b/arch/x86/kvm/Kconfig
@@ -64,6 +64,7 @@ config KVM_AMD
# OK, it's a little counter-intuitive to do this, but it puts it neatly under
# the virtualization menu.
+source drivers/vhost/Kconfig
source drivers/lguest/Kconfig
source drivers/virtio/Kconfig
diff --git a/drivers/Makefile b/drivers/Makefile
index 6ee53c7..81e3659 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -106,6 +106,7 @@ obj-$(CONFIG_HID) += hid/
obj-$(CONFIG_PPC_PS3) += ps3/
obj-$(CONFIG_OF) += of/
obj-$(CONFIG_SSB) += ssb/
+obj-$(CONFIG_VHOST_NET) += vhost/
obj-$(CONFIG_VIRTIO) += virtio/
obj-$(CONFIG_VLYNQ) += vlynq/
obj-$(CONFIG_STAGING) += staging/
diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig
new file mode 100644
index 0000000..9f409f4
--- /dev/null
+++ b/drivers/vhost/Kconfig
@@ -0,0 +1,11 @@
+config VHOST_NET
+ tristate "Host kernel accelerator for virtio net (EXPERIMENTAL)"
+ depends on NET && EVENTFD && EXPERIMENTAL
+ ---help---
+ This kernel module can be loaded in host kernel to accelerate
+ guest networking with virtio_net. Not to be confused with virtio_net
+ module itself which needs to be loaded in guest kernel.
+
+ To compile this driver as a module, choose M here: the module will
+ be called vhost_net.
+
diff --git a/drivers/vhost/Makefile b/drivers/vhost/Makefile
new file mode 100644
index 0000000..72dd020
--- /dev/null
+++ b/drivers/vhost/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_VHOST_NET) += vhost_net.o
+vhost_net-y := vhost.o net.o
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
new file mode 100644
index 0000000..22d5fef
--- /dev/null
+++ b/drivers/vhost/net.c
@@ -0,0 +1,648 @@
+/* Copyright (C) 2009 Red Hat, Inc.
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ *
+ * virtio-net server in host kernel.
+ */
+
+#include <linux/compat.h>
+#include <linux/eventfd.h>
+#include <linux/vhost.h>
+#include <linux/virtio_net.h>
+#include <linux/mmu_context.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/rcupdate.h>
+#include <linux/file.h>
+
+#include <linux/net.h>
+#include <linux/if_packet.h>
+#include <linux/if_arp.h>
+#include <linux/if_tun.h>
+
+#include <net/sock.h>
+
+#include "vhost.h"
+
+/* Max number of bytes transferred before requeueing the job.
+ * Using this limit prevents one virtqueue from starving others. */
+#define VHOST_NET_WEIGHT 0x80000
+
+enum {
+ VHOST_NET_VQ_RX = 0,
+ VHOST_NET_VQ_TX = 1,
+ VHOST_NET_VQ_MAX = 2,
+};
+
+enum vhost_net_poll_state {
+ VHOST_NET_POLL_DISABLED = 0,
+ VHOST_NET_POLL_STARTED = 1,
+ VHOST_NET_POLL_STOPPED = 2,
+};
+
+struct vhost_net {
+ struct vhost_dev dev;
+ struct vhost_virtqueue vqs[VHOST_NET_VQ_MAX];
+ struct vhost_poll poll[VHOST_NET_VQ_MAX];
+ /* Tells us whether we are polling a socket for TX.
+ * We only do this when socket buffer fills up.
+ * Protected by tx vq lock. */
+ enum vhost_net_poll_state tx_poll_state;
+};
+
+/* Pop first len bytes from iovec. Return number of segments used. */
+static int move_iovec_hdr(struct iovec *from, struct iovec *to,
+ size_t len, int iov_count)
+{
+ int seg = 0;
+ size_t size;
+ while (len && seg < iov_count) {
+ size = min(from->iov_len, len);
+ to->iov_base = from->iov_base;
+ to->iov_len = size;
+ from->iov_len -= size;
+ from->iov_base += size;
+ len -= size;
+ ++from;
+ ++to;
+ ++seg;
+ }
+ return seg;
+}
+
+/* Caller must have TX VQ lock */
+static void tx_poll_stop(struct vhost_net *net)
+{
+ if (likely(net->tx_poll_state != VHOST_NET_POLL_STARTED))
+ return;
+ vhost_poll_stop(net->poll + VHOST_NET_VQ_TX);
+ net->tx_poll_state = VHOST_NET_POLL_STOPPED;
+}
+
+/* Caller must have TX VQ lock */
+static void tx_poll_start(struct vhost_net *net, struct socket *sock)
+{
+ if (unlikely(net->tx_poll_state != VHOST_NET_POLL_STOPPED))
+ return;
+ vhost_poll_start(net->poll + VHOST_NET_VQ_TX, sock->file);
+ net->tx_poll_state = VHOST_NET_POLL_STARTED;
+}
+
+/* Expects to be always run from workqueue - which acts as
+ * read-size critical section for our kind of RCU. */
+static void handle_tx(struct vhost_net *net)
+{
+ struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX];
+ unsigned head, out, in, s;
+ struct msghdr msg = {
+ .msg_name = NULL,
+ .msg_namelen = 0,
+ .msg_control = NULL,
+ .msg_controllen = 0,
+ .msg_iov = vq->iov,
+ .msg_flags = MSG_DONTWAIT,
+ };
+ size_t len, total_len = 0;
+ int err, wmem;
+ size_t hdr_size;
+ struct socket *sock = rcu_dereference(vq->private_data);
+ if (!sock)
+ return;
+
+ wmem = atomic_read(&sock->sk->sk_wmem_alloc);
+ if (wmem >= sock->sk->sk_sndbuf)
+ return;
+
+ use_mm(net->dev.mm);
+ mutex_lock(&vq->mutex);
+ vhost_disable_notify(vq);
+
+ if (wmem < sock->sk->sk_sndbuf * 2)
+ tx_poll_stop(net);
+ hdr_size = vq->hdr_size;
+
+ for (;;) {
+ head = vhost_get_vq_desc(&net->dev, vq, vq->iov,
+ ARRAY_SIZE(vq->iov),
+ &out, &in,
+ NULL, NULL);
+ /* Nothing new? Wait for eventfd to tell us they refilled. */
+ if (head == vq->num) {
+ wmem = atomic_read(&sock->sk->sk_wmem_alloc);
+ if (wmem >= sock->sk->sk_sndbuf * 3 / 4) {
+ tx_poll_start(net, sock);
+ set_bit(SOCK_ASYNC_NOSPACE, &sock->flags);
+ break;
+ }
+ if (unlikely(vhost_enable_notify(vq))) {
+ vhost_disable_notify(vq);
+ continue;
+ }
+ break;
+ }
+ if (in) {
+ vq_err(vq, "Unexpected descriptor format for TX: "
+ "out %d, int %d\n", out, in);
+ break;
+ }
+ /* Skip header. TODO: support TSO. */
+ s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, out);
+ msg.msg_iovlen = out;
+ len = iov_length(vq->iov, out);
+ /* Sanity check */
+ if (!len) {
+ vq_err(vq, "Unexpected header len for TX: "
+ "%zd expected %zd\n",
+ iov_length(vq->hdr, s), hdr_size);
+ break;
+ }
+ /* TODO: Check specific error and bomb out unless ENOBUFS? */
+ err = sock->ops->sendmsg(NULL, sock, &msg, len);
+ if (unlikely(err < 0)) {
+ vhost_discard_vq_desc(vq);
+ tx_poll_start(net, sock);
+ break;
+ }
+ if (err != len)
+ pr_err("Truncated TX packet: "
+ " len %d != %zd\n", err, len);
+ vhost_add_used_and_signal(&net->dev, vq, head, 0);
+ total_len += len;
+ if (unlikely(total_len >= VHOST_NET_WEIGHT)) {
+ vhost_poll_queue(&vq->poll);
+ break;
+ }
+ }
+
+ mutex_unlock(&vq->mutex);
+ unuse_mm(net->dev.mm);
+}
+
+/* Expects to be always run from workqueue - which acts as
+ * read-size critical section for our kind of RCU. */
+static void handle_rx(struct vhost_net *net)
+{
+ struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX];
+ unsigned head, out, in, log, s;
+ struct vhost_log *vq_log;
+ struct msghdr msg = {
+ .msg_name = NULL,
+ .msg_namelen = 0,
+ .msg_control = NULL, /* FIXME: get and handle RX aux data. */
+ .msg_controllen = 0,
+ .msg_iov = vq->iov,
+ .msg_flags = MSG_DONTWAIT,
+ };
+
+ struct virtio_net_hdr hdr = {
+ .flags = 0,
+ .gso_type = VIRTIO_NET_HDR_GSO_NONE
+ };
+
+ size_t len, total_len = 0;
+ int err;
+ size_t hdr_size;
+ struct socket *sock = rcu_dereference(vq->private_data);
+ if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue))
+ return;
+
+ use_mm(net->dev.mm);
+ mutex_lock(&vq->mutex);
+ vhost_disable_notify(vq);
+ hdr_size = vq->hdr_size;
+
+ vq_log = unlikely(vhost_has_feature(&net->dev, VHOST_F_LOG_ALL)) ?
+ vq->log : NULL;
+
+ for (;;) {
+ head = vhost_get_vq_desc(&net->dev, vq, vq->iov,
+ ARRAY_SIZE(vq->iov),
+ &out, &in,
+ vq_log, &log);
+ /* OK, now we need to know about added descriptors. */
+ if (head == vq->num) {
+ if (unlikely(vhost_enable_notify(vq))) {
+ /* They have slipped one in as we were
+ * doing that: check again. */
+ vhost_disable_notify(vq);
+ continue;
+ }
+ /* Nothing new? Wait for eventfd to tell us
+ * they refilled. */
+ break;
+ }
+ /* We don't need to be notified again. */
+ if (out) {
+ vq_err(vq, "Unexpected descriptor format for RX: "
+ "out %d, int %d\n",
+ out, in);
+ break;
+ }
+ /* Skip header. TODO: support TSO/mergeable rx buffers. */
+ s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, in);
+ msg.msg_iovlen = in;
+ len = iov_length(vq->iov, in);
+ /* Sanity check */
+ if (!len) {
+ vq_err(vq, "Unexpected header len for RX: "
+ "%zd expected %zd\n",
+ iov_length(vq->hdr, s), hdr_size);
+ break;
+ }
+ err = sock->ops->recvmsg(NULL, sock, &msg,
+ len, MSG_DONTWAIT | MSG_TRUNC);
+ /* TODO: Check specific error and bomb out unless EAGAIN? */
+ if (err < 0) {
+ vhost_discard_vq_desc(vq);
+ break;
+ }
+ /* TODO: Should check and handle checksum. */
+ if (err > len) {
+ pr_err("Discarded truncated rx packet: "
+ " len %d > %zd\n", err, len);
+ vhost_discard_vq_desc(vq);
+ continue;
+ }
+ len = err;
+ err = memcpy_toiovec(vq->hdr, (unsigned char *)&hdr, hdr_size);
+ if (err) {
+ vq_err(vq, "Unable to write vnet_hdr at addr %p: %d\n",
+ vq->iov->iov_base, err);
+ break;
+ }
+ len += hdr_size;
+ vhost_add_used_and_signal(&net->dev, vq, head, len);
+ if (unlikely(vq_log))
+ vhost_log_write(vq, vq_log, log, len);
+ total_len += len;
+ if (unlikely(total_len >= VHOST_NET_WEIGHT)) {
+ vhost_poll_queue(&vq->poll);
+ break;
+ }
+ }
+
+ mutex_unlock(&vq->mutex);
+ unuse_mm(net->dev.mm);
+}
+
+static void handle_tx_kick(struct work_struct *work)
+{
+ struct vhost_virtqueue *vq;
+ struct vhost_net *net;
+ vq = container_of(work, struct vhost_virtqueue, poll.work);
+ net = container_of(vq->dev, struct vhost_net, dev);
+ handle_tx(net);
+}
+
+static void handle_rx_kick(struct work_struct *work)
+{
+ struct vhost_virtqueue *vq;
+ struct vhost_net *net;
+ vq = container_of(work, struct vhost_virtqueue, poll.work);
+ net = container_of(vq->dev, struct vhost_net, dev);
+ handle_rx(net);
+}
+
+static void handle_tx_net(struct work_struct *work)
+{
+ struct vhost_net *net;
+ net = container_of(work, struct vhost_net, poll[VHOST_NET_VQ_TX].work);
+ handle_tx(net);
+}
+
+static void handle_rx_net(struct work_struct *work)
+{
+ struct vhost_net *net;
+ net = container_of(work, struct vhost_net, poll[VHOST_NET_VQ_RX].work);
+ handle_rx(net);
+}
+
+static int vhost_net_open(struct inode *inode, struct file *f)
+{
+ struct vhost_net *n = kmalloc(sizeof *n, GFP_KERNEL);
+ int r;
+ if (!n)
+ return -ENOMEM;
+ f->private_data = n;
+ n->vqs[VHOST_NET_VQ_TX].handle_kick = handle_tx_kick;
+ n->vqs[VHOST_NET_VQ_RX].handle_kick = handle_rx_kick;
+ r = vhost_dev_init(&n->dev, n->vqs, VHOST_NET_VQ_MAX);
+ if (r < 0) {
+ kfree(n);
+ return r;
+ }
+
+ vhost_poll_init(n->poll + VHOST_NET_VQ_TX, handle_tx_net, POLLOUT);
+ vhost_poll_init(n->poll + VHOST_NET_VQ_RX, handle_rx_net, POLLIN);
+ n->tx_poll_state = VHOST_NET_POLL_DISABLED;
+ return 0;
+}
+
+static void vhost_net_disable_vq(struct vhost_net *n,
+ struct vhost_virtqueue *vq)
+{
+ if (!vq->private_data)
+ return;
+ if (vq == n->vqs + VHOST_NET_VQ_TX) {
+ tx_poll_stop(n);
+ n->tx_poll_state = VHOST_NET_POLL_DISABLED;
+ } else
+ vhost_poll_stop(n->poll + VHOST_NET_VQ_RX);
+}
+
+static void vhost_net_enable_vq(struct vhost_net *n,
+ struct vhost_virtqueue *vq)
+{
+ struct socket *sock = vq->private_data;
+ if (!sock)
+ return;
+ if (vq == n->vqs + VHOST_NET_VQ_TX) {
+ n->tx_poll_state = VHOST_NET_POLL_STOPPED;
+ tx_poll_start(n, sock);
+ } else
+ vhost_poll_start(n->poll + VHOST_NET_VQ_RX, sock->file);
+}
+
+static struct socket *vhost_net_stop_vq(struct vhost_net *n,
+ struct vhost_virtqueue *vq)
+{
+ struct socket *sock;
+
+ mutex_lock(&vq->mutex);
+ sock = vq->private_data;
+ vhost_net_disable_vq(n, vq);
+ rcu_assign_pointer(vq->private_data, NULL);
+ mutex_unlock(&vq->mutex);
+ return sock;
+}
+
+static void vhost_net_stop(struct vhost_net *n, struct socket **tx_sock,
+ struct socket **rx_sock)
+{
+ *tx_sock = vhost_net_stop_vq(n, n->vqs + VHOST_NET_VQ_TX);
+ *rx_sock = vhost_net_stop_vq(n, n->vqs + VHOST_NET_VQ_RX);
+}
+
+static void vhost_net_flush_vq(struct vhost_net *n, int index)
+{
+ vhost_poll_flush(n->poll + index);
+ vhost_poll_flush(&n->dev.vqs[index].poll);
+}
+
+static void vhost_net_flush(struct vhost_net *n)
+{
+ vhost_net_flush_vq(n, VHOST_NET_VQ_TX);
+ vhost_net_flush_vq(n, VHOST_NET_VQ_RX);
+}
+
+static int vhost_net_release(struct inode *inode, struct file *f)
+{
+ struct vhost_net *n = f->private_data;
+ struct socket *tx_sock;
+ struct socket *rx_sock;
+
+ vhost_net_stop(n, &tx_sock, &rx_sock);
+ vhost_net_flush(n);
+ vhost_dev_cleanup(&n->dev);
+ if (tx_sock)
+ fput(tx_sock->file);
+ if (rx_sock)
+ fput(rx_sock->file);
+ /* We do an extra flush before freeing memory,
+ * since jobs can re-queue themselves. */
+ vhost_net_flush(n);
+ kfree(n);
+ return 0;
+}
+
+static struct socket *get_raw_socket(int fd)
+{
+ struct {
+ struct sockaddr_ll sa;
+ char buf[MAX_ADDR_LEN];
+ } uaddr;
+ int uaddr_len = sizeof uaddr, r;
+ struct socket *sock = sockfd_lookup(fd, &r);
+ if (!sock)
+ return ERR_PTR(-ENOTSOCK);
+
+ /* Parameter checking */
+ if (sock->sk->sk_type != SOCK_RAW) {
+ r = -ESOCKTNOSUPPORT;
+ goto err;
+ }
+
+ r = sock->ops->getname(sock, (struct sockaddr *)&uaddr.sa,
+ &uaddr_len, 0);
+ if (r)
+ goto err;
+
+ if (uaddr.sa.sll_family != AF_PACKET) {
+ r = -EPFNOSUPPORT;
+ goto err;
+ }
+ return sock;
+err:
+ fput(sock->file);
+ return ERR_PTR(r);
+}
+
+static struct socket *get_tun_socket(int fd)
+{
+ struct file *file = fget(fd);
+ struct socket *sock;
+ if (!file)
+ return ERR_PTR(-EBADF);
+ sock = tun_get_socket(file);
+ if (IS_ERR(sock))
+ fput(file);
+ return sock;
+}
+
+static struct socket *get_socket(int fd)
+{
+ struct socket *sock;
+ if (fd == -1)
+ return NULL;
+ sock = get_raw_socket(fd);
+ if (!IS_ERR(sock))
+ return sock;
+ sock = get_tun_socket(fd);
+ if (!IS_ERR(sock))
+ return sock;
+ return ERR_PTR(-ENOTSOCK);
+}
+
+static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
+{
+ struct socket *sock, *oldsock;
+ struct vhost_virtqueue *vq;
+ int r;
+
+ mutex_lock(&n->dev.mutex);
+ r = vhost_dev_check_owner(&n->dev);
+ if (r)
+ goto err;
+
+ if (index >= VHOST_NET_VQ_MAX) {
+ r = -ENOBUFS;
+ goto err;
+ }
+ vq = n->vqs + index;
+ mutex_lock(&vq->mutex);
+ sock = get_socket(fd);
+ if (IS_ERR(sock)) {
+ r = PTR_ERR(sock);
+ goto err;
+ }
+
+ /* start polling new socket */
+ oldsock = vq->private_data;
+ if (sock == oldsock)
+ goto done;
+
+ vhost_net_disable_vq(n, vq);
+ rcu_assign_pointer(vq->private_data, sock);
+ vhost_net_enable_vq(n, vq);
+ mutex_unlock(&vq->mutex);
+done:
+ mutex_unlock(&n->dev.mutex);
+ if (oldsock) {
+ vhost_net_flush_vq(n, index);
+ fput(oldsock->file);
+ }
+ return r;
+err:
+ mutex_unlock(&n->dev.mutex);
+ return r;
+}
+
+static long vhost_net_reset_owner(struct vhost_net *n)
+{
+ struct socket *tx_sock = NULL;
+ struct socket *rx_sock = NULL;
+ long err;
+ mutex_lock(&n->dev.mutex);
+ err = vhost_dev_check_owner(&n->dev);
+ if (err)
+ goto done;
+ vhost_net_stop(n, &tx_sock, &rx_sock);
+ vhost_net_flush(n);
+ err = vhost_dev_reset_owner(&n->dev);
+done:
+ mutex_unlock(&n->dev.mutex);
+ if (tx_sock)
+ fput(tx_sock->file);
+ if (rx_sock)
+ fput(rx_sock->file);
+ return err;
+}
+
+static void vhost_net_set_features(struct vhost_net *n, u64 features)
+{
+ size_t hdr_size = features & (1 << VHOST_NET_F_VIRTIO_NET_HDR) ?
+ sizeof(struct virtio_net_hdr) : 0;
+ int i;
+ mutex_lock(&n->dev.mutex);
+ n->dev.acked_features = features;
+ smp_wmb();
+ for (i = 0; i < VHOST_NET_VQ_MAX; ++i) {
+ mutex_lock(&n->vqs[i].mutex);
+ n->vqs[i].hdr_size = hdr_size;
+ mutex_unlock(&n->vqs[i].mutex);
+ }
+ mutex_unlock(&n->dev.mutex);
+ vhost_net_flush(n);
+}
+
+static long vhost_net_ioctl(struct file *f, unsigned int ioctl,
+ unsigned long arg)
+{
+ struct vhost_net *n = f->private_data;
+ void __user *argp = (void __user *)arg;
+ u32 __user *featurep = argp;
+ struct vhost_vring_file backend;
+ u64 features;
+ int r;
+ switch (ioctl) {
+ case VHOST_NET_SET_BACKEND:
+ r = copy_from_user(&backend, argp, sizeof backend);
+ if (r < 0)
+ return r;
+ return vhost_net_set_backend(n, backend.index, backend.fd);
+ case VHOST_GET_FEATURES:
+ features = VHOST_FEATURES;
+ return put_user(features, featurep);
+ case VHOST_SET_FEATURES:
+ r = get_user(features, featurep);
+ /* No features for now */
+ if (r < 0)
+ return r;
+ if (features & ~VHOST_FEATURES)
+ return -EOPNOTSUPP;
+ vhost_net_set_features(n, features);
+ return 0;
+ case VHOST_RESET_OWNER:
+ return vhost_net_reset_owner(n);
+ default:
+ r = vhost_dev_ioctl(&n->dev, ioctl, arg);
+ vhost_net_flush(n);
+ return r;
+ }
+}
+
+#ifdef CONFIG_COMPAT
+static long vhost_net_compat_ioctl(struct file *f, unsigned int ioctl,
+ unsigned long arg)
+{
+ return vhost_net_ioctl(f, ioctl, (unsigned long)compat_ptr(arg));
+}
+#endif
+
+const static struct file_operations vhost_net_fops = {
+ .owner = THIS_MODULE,
+ .release = vhost_net_release,
+ .unlocked_ioctl = vhost_net_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = vhost_net_compat_ioctl,
+#endif
+ .open = vhost_net_open,
+};
+
+static struct miscdevice vhost_net_misc = {
+ VHOST_NET_MINOR,
+ "vhost-net",
+ &vhost_net_fops,
+};
+
+int vhost_net_init(void)
+{
+ int r = vhost_init();
+ if (r)
+ goto err_init;
+ r = misc_register(&vhost_net_misc);
+ if (r)
+ goto err_reg;
+ return 0;
+err_reg:
+ vhost_cleanup();
+err_init:
+ return r;
+
+}
+module_init(vhost_net_init);
+
+void vhost_net_exit(void)
+{
+ misc_deregister(&vhost_net_misc);
+ vhost_cleanup();
+}
+module_exit(vhost_net_exit);
+
+MODULE_VERSION("0.0.1");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Michael S. Tsirkin");
+MODULE_DESCRIPTION("Host kernel accelerator for virtio net");
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
new file mode 100644
index 0000000..97233d5
--- /dev/null
+++ b/drivers/vhost/vhost.c
@@ -0,0 +1,965 @@
+/* Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2006 Rusty Russell IBM Corporation
+ *
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *
+ * Inspiration, some code, and most witty comments come from
+ * Documentation/lguest/lguest.c, by Rusty Russell
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ *
+ * Generic code for virtio server in host kernel.
+ */
+
+#include <linux/eventfd.h>
+#include <linux/vhost.h>
+#include <linux/virtio_net.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/rcupdate.h>
+#include <linux/poll.h>
+#include <linux/file.h>
+#include <linux/highmem.h>
+
+#include <linux/net.h>
+#include <linux/if_packet.h>
+#include <linux/if_arp.h>
+
+#include <net/sock.h>
+
+#include "vhost.h"
+
+enum {
+ VHOST_MEMORY_MAX_NREGIONS = 64,
+ VHOST_MEMORY_F_LOG = 0x1,
+};
+
+static struct workqueue_struct *vhost_workqueue;
+
+static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh,
+ poll_table *pt)
+{
+ struct vhost_poll *poll;
+ poll = container_of(pt, struct vhost_poll, table);
+
+ poll->wqh = wqh;
+ add_wait_queue(wqh, &poll->wait);
+}
+
+static int vhost_poll_wakeup(wait_queue_t *wait, unsigned mode, int sync,
+ void *key)
+{
+ struct vhost_poll *poll;
+ poll = container_of(wait, struct vhost_poll, wait);
+ if (!((unsigned long)key & poll->mask))
+ return 0;
+
+ queue_work(vhost_workqueue, &poll->work);
+ return 0;
+}
+
+/* Init poll structure */
+void vhost_poll_init(struct vhost_poll *poll, work_func_t func,
+ unsigned long mask)
+{
+ INIT_WORK(&poll->work, func);
+ init_waitqueue_func_entry(&poll->wait, vhost_poll_wakeup);
+ init_poll_funcptr(&poll->table, vhost_poll_func);
+ poll->mask = mask;
+}
+
+/* Start polling a file. We add ourselves to file's wait queue. The caller must
+ * keep a reference to a file until after vhost_poll_stop is called. */
+void vhost_poll_start(struct vhost_poll *poll, struct file *file)
+{
+ unsigned long mask;
+ mask = file->f_op->poll(file, &poll->table);
+ if (mask)
+ vhost_poll_wakeup(&poll->wait, 0, 0, (void *)mask);
+}
+
+/* Stop polling a file. After this function returns, it becomes safe to drop the
+ * file reference. You must also flush afterwards. */
+void vhost_poll_stop(struct vhost_poll *poll)
+{
+ remove_wait_queue(poll->wqh, &poll->wait);
+}
+
+/* Flush any work that has been scheduled. When calling this, don't hold any
+ * locks that are also used by the callback. */
+void vhost_poll_flush(struct vhost_poll *poll)
+{
+ flush_work(&poll->work);
+}
+
+void vhost_poll_queue(struct vhost_poll *poll)
+{
+ queue_work(vhost_workqueue, &poll->work);
+}
+
+static void vhost_vq_reset(struct vhost_dev *dev,
+ struct vhost_virtqueue *vq)
+{
+ vq->num = 1;
+ vq->desc = NULL;
+ vq->avail = NULL;
+ vq->used = NULL;
+ vq->last_avail_idx = 0;
+ vq->avail_idx = 0;
+ vq->last_used_idx = 0;
+ vq->used_flags = 0;
+ vq->used_flags = 0;
+ vq->log_used = false;
+ vq->log_addr = -1ull;
+ vq->hdr_size = 0;
+ vq->private_data = NULL;
+ vq->log_base = NULL;
+ vq->error_ctx = NULL;
+ vq->error = NULL;
+ vq->kick = NULL;
+ vq->call_ctx = NULL;
+ vq->call = NULL;
+}
+
+long vhost_dev_init(struct vhost_dev *dev,
+ struct vhost_virtqueue *vqs, int nvqs)
+{
+ int i;
+ dev->vqs = vqs;
+ dev->nvqs = nvqs;
+ mutex_init(&dev->mutex);
+ dev->log_ctx = NULL;
+ dev->log_file = NULL;
+ dev->memory = NULL;
+ dev->mm = NULL;
+
+ for (i = 0; i < dev->nvqs; ++i) {
+ dev->vqs[i].dev = dev;
+ mutex_init(&dev->vqs[i].mutex);
+ vhost_vq_reset(dev, dev->vqs + i);
+ if (dev->vqs[i].handle_kick)
+ vhost_poll_init(&dev->vqs[i].poll,
+ dev->vqs[i].handle_kick,
+ POLLIN);
+ }
+ return 0;
+}
+
+/* Caller should have device mutex */
+long vhost_dev_check_owner(struct vhost_dev *dev)
+{
+ /* Are you the owner? If not, I don't think you mean to do that */
+ return dev->mm == current->mm ? 0 : -EPERM;
+}
+
+/* Caller should have device mutex */
+static long vhost_dev_set_owner(struct vhost_dev *dev)
+{
+ /* Is there an owner already? */
+ if (dev->mm)
+ return -EBUSY;
+ /* No owner, become one */
+ dev->mm = get_task_mm(current);
+ return 0;
+}
+
+/* Caller should have device mutex */
+long vhost_dev_reset_owner(struct vhost_dev *dev)
+{
+ struct vhost_memory *memory;
+
+ /* Restore memory to default 1:1 mapping. */
+ memory = kmalloc(offsetof(struct vhost_memory, regions) +
+ 2 * sizeof *memory->regions, GFP_KERNEL);
+ if (!memory)
+ return -ENOMEM;
+
+ vhost_dev_cleanup(dev);
+
+ memory->nregions = 2;
+ memory->regions[0].guest_phys_addr = 1;
+ memory->regions[0].userspace_addr = 1;
+ memory->regions[0].memory_size = ~0ULL;
+ memory->regions[1].guest_phys_addr = 0;
+ memory->regions[1].userspace_addr = 0;
+ memory->regions[1].memory_size = 1;
+ dev->memory = memory;
+ return 0;
+}
+
+/* Caller should have device mutex */
+void vhost_dev_cleanup(struct vhost_dev *dev)
+{
+ int i;
+ for (i = 0; i < dev->nvqs; ++i) {
+ if (dev->vqs[i].kick && dev->vqs[i].handle_kick) {
+ vhost_poll_stop(&dev->vqs[i].poll);
+ vhost_poll_flush(&dev->vqs[i].poll);
+ }
+ if (dev->vqs[i].error_ctx)
+ eventfd_ctx_put(dev->vqs[i].error_ctx);
+ if (dev->vqs[i].error)
+ fput(dev->vqs[i].error);
+ if (dev->vqs[i].kick)
+ fput(dev->vqs[i].kick);
+ if (dev->vqs[i].call_ctx)
+ eventfd_ctx_put(dev->vqs[i].call_ctx);
+ if (dev->vqs[i].call)
+ fput(dev->vqs[i].call);
+ vhost_vq_reset(dev, dev->vqs + i);
+ }
+ if (dev->log_ctx)
+ eventfd_ctx_put(dev->log_ctx);
+ dev->log_ctx = NULL;
+ if (dev->log_file)
+ fput(dev->log_file);
+ dev->log_file = NULL;
+ /* No one will access memory at this point */
+ kfree(dev->memory);
+ dev->memory = NULL;
+ if (dev->mm)
+ mmput(dev->mm);
+ dev->mm = NULL;
+}
+
+static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
+{
+ struct vhost_memory mem, *newmem, *oldmem;
+ unsigned long size = offsetof(struct vhost_memory, regions);
+ long r;
+ r = copy_from_user(&mem, m, size);
+ if (r)
+ return r;
+ if (mem.padding)
+ return -EOPNOTSUPP;
+ if (mem.nregions > VHOST_MEMORY_MAX_NREGIONS)
+ return -E2BIG;
+ newmem = kmalloc(size + mem.nregions * sizeof *m->regions, GFP_KERNEL);
+ if (!newmem)
+ return -ENOMEM;
+
+ memcpy(newmem, &mem, size);
+ r = copy_from_user(newmem->regions, m->regions,
+ mem.nregions * sizeof *m->regions);
+ if (r) {
+ kfree(newmem);
+ return r;
+ }
+ oldmem = d->memory;
+ rcu_assign_pointer(d->memory, newmem);
+ synchronize_rcu();
+ kfree(oldmem);
+ return 0;
+}
+
+static int init_used(struct vhost_virtqueue *vq,
+ struct vring_used __user *used)
+{
+ int r = put_user(vq->used_flags, &used->flags);
+ if (r)
+ return r;
+ return get_user(vq->last_used_idx, &used->idx);
+}
+
+static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp)
+{
+ struct file *eventfp, *filep = NULL,
+ *pollstart = NULL, *pollstop = NULL;
+ struct eventfd_ctx *ctx = NULL;
+ u32 __user *idxp = argp;
+ struct vhost_virtqueue *vq;
+ struct vhost_vring_state s;
+ struct vhost_vring_file f;
+ struct vhost_vring_addr a;
+ u32 idx;
+ long r;
+
+ r = get_user(idx, idxp);
+ if (r < 0)
+ return r;
+ if (idx > d->nvqs)
+ return -ENOBUFS;
+
+ vq = d->vqs + idx;
+
+ mutex_lock(&vq->mutex);
+
+ switch (ioctl) {
+ case VHOST_SET_VRING_NUM:
+ r = copy_from_user(&s, argp, sizeof s);
+ if (r < 0)
+ break;
+ if (!s.num || s.num > 0xffff || (s.num & (s.num - 1))) {
+ r = -EINVAL;
+ break;
+ }
+ vq->num = s.num;
+ break;
+ case VHOST_SET_VRING_BASE:
+ r = copy_from_user(&s, argp, sizeof s);
+ if (r < 0)
+ break;
+ if (s.num > 0xffff) {
+ r = -EINVAL;
+ break;
+ }
+ vq->last_avail_idx = s.num;
+ /* Forget the cached index value. */
+ vq->avail_idx = vq->last_avail_idx;
+ break;
+ case VHOST_GET_VRING_BASE:
+ s.index = idx;
+ s.num = vq->last_avail_idx;
+ r = copy_to_user(argp, &s, sizeof s);
+ break;
+ case VHOST_SET_VRING_ADDR:
+ r = copy_from_user(&a, argp, sizeof a);
+ if (r < 0)
+ break;
+ if (a.flags & ~(0x1 << VHOST_VRING_F_LOG)) {
+ r = -EOPNOTSUPP;
+ break;
+ }
+ if ((u64)(unsigned long)a.desc_user_addr != a.desc_user_addr ||
+ (u64)(unsigned long)a.used_user_addr != a.used_user_addr ||
+ (u64)(unsigned long)a.avail_user_addr != a.avail_user_addr) {
+ r = -EFAULT;
+ break;
+ }
+ if ((a.avail_user_addr & (sizeof *vq->avail->ring - 1)) ||
+ (a.used_user_addr & (sizeof *vq->used->ring - 1)) ||
+ (a.log_guest_addr & (sizeof *vq->used->ring - 1))) {
+ r = -EINVAL;
+ break;
+ }
+ r = init_used(vq, (struct vring_used __user *)a.used_user_addr);
+ if (r)
+ break;
+ vq->log_used = !!(a.flags & (0x1 << VHOST_VRING_F_LOG));
+ vq->desc = (void __user *)(unsigned long)a.desc_user_addr;
+ vq->avail = (void __user *)(unsigned long)a.avail_user_addr;
+ vq->log_addr = a.log_guest_addr;
+ vq->used = (void __user *)(unsigned long)a.used_user_addr;
+ break;
+ case VHOST_SET_VRING_KICK:
+ r = copy_from_user(&f, argp, sizeof f);
+ if (r < 0)
+ break;
+ eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd);
+ if (IS_ERR(eventfp))
+ return PTR_ERR(eventfp);
+ if (eventfp != vq->kick) {
+ pollstop = filep = vq->kick;
+ pollstart = vq->kick = eventfp;
+ } else
+ filep = eventfp;
+ break;
+ case VHOST_SET_VRING_CALL:
+ r = copy_from_user(&f, argp, sizeof f);
+ if (r < 0)
+ break;
+ eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd);
+ if (IS_ERR(eventfp))
+ return PTR_ERR(eventfp);
+ if (eventfp != vq->call) {
+ filep = vq->call;
+ ctx = vq->call_ctx;
+ vq->call = eventfp;
+ vq->call_ctx = eventfp ?
+ eventfd_ctx_fileget(eventfp) : NULL;
+ } else
+ filep = eventfp;
+ break;
+ case VHOST_SET_VRING_ERR:
+ r = copy_from_user(&f, argp, sizeof f);
+ if (r < 0)
+ break;
+ eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd);
+ if (IS_ERR(eventfp))
+ return PTR_ERR(eventfp);
+ if (eventfp != vq->error) {
+ filep = vq->error;
+ vq->error = eventfp;
+ ctx = vq->error_ctx;
+ vq->error_ctx = eventfp ?
+ eventfd_ctx_fileget(eventfp) : NULL;
+ } else
+ filep = eventfp;
+ break;
+ default:
+ r = -ENOIOCTLCMD;
+ }
+
+ if (pollstop && vq->handle_kick)
+ vhost_poll_stop(&vq->poll);
+
+ if (ctx)
+ eventfd_ctx_put(ctx);
+ if (filep)
+ fput(filep);
+
+ if (pollstart && vq->handle_kick)
+ vhost_poll_start(&vq->poll, vq->kick);
+
+ mutex_unlock(&vq->mutex);
+
+ if (pollstop && vq->handle_kick)
+ vhost_poll_flush(&vq->poll);
+ return r;
+}
+
+long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ struct file *eventfp, *filep = NULL;
+ struct eventfd_ctx *ctx = NULL;
+ u64 p;
+ long r;
+ int i, fd;
+
+ mutex_lock(&d->mutex);
+ /* If you are not the owner, you can become one */
+ if (ioctl == VHOST_SET_OWNER) {
+ r = vhost_dev_set_owner(d);
+ goto done;
+ }
+
+ /* You must be the owner to do anything else */
+ r = vhost_dev_check_owner(d);
+ if (r)
+ goto done;
+
+ switch (ioctl) {
+ case VHOST_SET_MEM_TABLE:
+ r = vhost_set_memory(d, argp);
+ break;
+ case VHOST_SET_LOG_BASE:
+ r = copy_from_user(&p, argp, sizeof p);
+ if (r < 0)
+ break;
+ if ((u64)(unsigned long)p != p) {
+ r = -EFAULT;
+ break;
+ }
+ for (i = 0; i < d->nvqs; ++i) {
+ mutex_lock(&d->vqs[i].mutex);
+ d->vqs[i].log_base = (void __user *)(unsigned long)p;
+ mutex_unlock(&d->vqs[i].mutex);
+ }
+ break;
+ case VHOST_SET_LOG_FD:
+ r = get_user(fd, (int __user *)argp);
+ if (r < 0)
+ break;
+ eventfp = fd == -1 ? NULL : eventfd_fget(fd);
+ if (IS_ERR(eventfp)) {
+ r = PTR_ERR(eventfp);
+ break;
+ }
+ if (eventfp != d->log_file) {
+ filep = d->log_file;
+ ctx = d->log_ctx;
+ d->log_ctx = eventfp ?
+ eventfd_ctx_fileget(eventfp) : NULL;
+ } else
+ filep = eventfp;
+ for (i = 0; i < d->nvqs; ++i) {
+ mutex_lock(&d->vqs[i].mutex);
+ d->vqs[i].log_ctx = d->log_ctx;
+ mutex_unlock(&d->vqs[i].mutex);
+ }
+ if (ctx)
+ eventfd_ctx_put(ctx);
+ if (filep)
+ fput(filep);
+ break;
+ default:
+ r = vhost_set_vring(d, ioctl, argp);
+ break;
+ }
+done:
+ mutex_unlock(&d->mutex);
+ return r;
+}
+
+static const struct vhost_memory_region *find_region(struct vhost_memory *mem,
+ __u64 addr, __u32 len)
+{
+ struct vhost_memory_region *reg;
+ int i;
+ /* linear search is not brilliant, but we really have on the order of 6
+ * regions in practice */
+ for (i = 0; i < mem->nregions; ++i) {
+ reg = mem->regions + i;
+ if (reg->guest_phys_addr <= addr &&
+ reg->guest_phys_addr + reg->memory_size - 1 >= addr)
+ return reg;
+ }
+ return NULL;
+}
+
+/* TODO: This is really inefficient. We need something like get_user()
+ * (instruction directly accesses the data, with an exception table entry
+ * returning -EFAULT). See Documentation/x86/exception-tables.txt.
+ */
+static int set_bit_to_user(int nr, void __user *addr)
+{
+ unsigned long log = (unsigned long)addr;
+ struct page *page;
+ void *base;
+ int bit = nr + (log % PAGE_SIZE) * 8;
+ int r;
+ r = get_user_pages_fast(log, 1, 1, &page);
+ if (r)
+ return r;
+ base = kmap_atomic(page, KM_USER0);
+ set_bit(bit, base);
+ kunmap_atomic(base, KM_USER0);
+ set_page_dirty_lock(page);
+ put_page(page);
+ return 0;
+}
+
+static int log_write(void __user *log_base,
+ u64 write_address, u64 write_length)
+{
+ int r;
+ if (!write_length)
+ return 0;
+ write_address /= VHOST_PAGE_SIZE;
+ for (;;) {
+ u64 base = (u64)(unsigned long)log_base;
+ u64 log = base + write_address / 8;
+ int bit = write_address % 8;
+ if ((u64)(unsigned long)log != log)
+ return -EFAULT;
+ r = set_bit_to_user(bit, (void __user *)(unsigned long)log);
+ if (r < 0)
+ return r;
+ if (write_length <= VHOST_PAGE_SIZE)
+ break;
+ write_length -= VHOST_PAGE_SIZE;
+ write_address += VHOST_PAGE_SIZE;
+ }
+ return r;
+}
+
+int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
+ unsigned int log_num, u64 len)
+{
+ int i, r;
+
+ /* Make sure data written is seen before log. */
+ wmb();
+ for (i = 0; i < log_num; ++i) {
+ u64 l = min(log[i].len, len);
+ r = log_write(vq->log_base, log[i].addr, l);
+ if (r < 0)
+ return r;
+ len -= l;
+ if (!len)
+ return 0;
+ }
+ if (vq->log_ctx)
+ eventfd_signal(vq->log_ctx, 1);
+ /* Length written exceeds what we have stored. This is a bug. */
+ BUG();
+ return 0;
+}
+
+int translate_desc(struct vhost_dev *dev, u64 addr, u32 len,
+ struct iovec iov[], int iov_size)
+{
+ const struct vhost_memory_region *reg;
+ struct vhost_memory *mem;
+ struct iovec *_iov;
+ u64 s = 0;
+ int ret = 0;
+
+ rcu_read_lock();
+
+ mem = rcu_dereference(dev->memory);
+ while ((u64)len > s) {
+ u64 size;
+ if (ret >= iov_size) {
+ ret = -ENOBUFS;
+ break;
+ }
+ reg = find_region(mem, addr, len);
+ if (!reg) {
+ ret = -EFAULT;
+ break;
+ }
+ _iov = iov + ret;
+ size = reg->memory_size - addr + reg->guest_phys_addr;
+ _iov->iov_len = min((u64)len, size);
+ _iov->iov_base = (void *)(unsigned long)
+ (reg->userspace_addr + addr - reg->guest_phys_addr);
+ s += size;
+ addr += size;
+ ++ret;
+ }
+
+ rcu_read_unlock();
+ return ret;
+}
+
+/* Each buffer in the virtqueues is actually a chain of descriptors. This
+ * function returns the next descriptor in the chain,
+ * or -1U if we're at the end. */
+static unsigned next_desc(struct vring_desc *desc)
+{
+ unsigned int next;
+
+ /* If this descriptor says it doesn't chain, we're done. */
+ if (!(desc->flags & VRING_DESC_F_NEXT))
+ return -1U;
+
+ /* Check they're not leading us off end of descriptors. */
+ next = desc->next;
+ /* Make sure compiler knows to grab that: we don't want it changing! */
+ /* We will use the result as an index in an array, so most
+ * architectures only need a compiler barrier here. */
+ read_barrier_depends();
+
+ return next;
+}
+
+static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq,
+ struct iovec iov[], unsigned int iov_size,
+ unsigned int *out_num, unsigned int *in_num,
+ struct vhost_log *log, unsigned int *log_num,
+ struct vring_desc *indirect)
+{
+ struct vring_desc desc;
+ unsigned int i = 0, count, found = 0;
+ int ret;
+
+ /* Sanity check */
+ if (indirect->len % sizeof desc) {
+ vq_err(vq, "Invalid length in indirect descriptor: "
+ "len 0x%llx not multiple of 0x%zx\n",
+ (unsigned long long)indirect->len,
+ sizeof desc);
+ return -EINVAL;
+ }
+
+ ret = translate_desc(dev, indirect->addr, indirect->len, vq->indirect,
+ ARRAY_SIZE(vq->indirect));
+ if (ret < 0) {
+ vq_err(vq, "Translation failure %d in indirect.\n", ret);
+ return ret;
+ }
+
+ /* We will use the result as an address to read from, so most
+ * architectures only need a compiler barrier here. */
+ read_barrier_depends();
+
+ count = indirect->len / sizeof desc;
+ /* Buffers are chained via a 16 bit next field, so
+ * we can have at most 2^16 of these. */
+ if (count > USHORT_MAX + 1) {
+ vq_err(vq, "Indirect buffer length too big: %d\n",
+ indirect->len);
+ return -E2BIG;
+ }
+
+ do {
+ unsigned iov_count = *in_num + *out_num;
+ if (++found > count) {
+ vq_err(vq, "Loop detected: last one at %u "
+ "indirect size %u\n",
+ i, count);
+ return -EINVAL;
+ }
+ if (memcpy_fromiovec((unsigned char *)&desc, vq->indirect,
+ sizeof desc)) {
+ vq_err(vq, "Failed indirect descriptor: idx %d, %zx\n",
+ i, (size_t)indirect->addr + i * sizeof desc);
+ return -EINVAL;
+ }
+ if (desc.flags & VRING_DESC_F_INDIRECT) {
+ vq_err(vq, "Nested indirect descriptor: idx %d, %zx\n",
+ i, (size_t)indirect->addr + i * sizeof desc);
+ return -EINVAL;
+ }
+
+ ret = translate_desc(dev, desc.addr, desc.len, iov + iov_count,
+ iov_size - iov_count);
+ if (ret < 0) {
+ vq_err(vq, "Translation failure %d indirect idx %d\n",
+ ret, i);
+ return ret;
+ }
+ /* If this is an input descriptor, increment that count. */
+ if (desc.flags & VRING_DESC_F_WRITE) {
+ *in_num += ret;
+ if (unlikely(log)) {
+ log[*log_num].addr = desc.addr;
+ log[*log_num].len = desc.len;
+ ++*log_num;
+ }
+ } else {
+ /* If it's an output descriptor, they're all supposed
+ * to come before any input descriptors. */
+ if (*in_num) {
+ vq_err(vq, "Indirect descriptor "
+ "has out after in: idx %d\n", i);
+ return -EINVAL;
+ }
+ *out_num += ret;
+ }
+ } while ((i = next_desc(&desc)) != -1);
+ return 0;
+}
+
+/* This looks in the virtqueue and for the first available buffer, and converts
+ * it to an iovec for convenient access. Since descriptors consist of some
+ * number of output then some number of input descriptors, it's actually two
+ * iovecs, but we pack them into one and note how many of each there were.
+ *
+ * This function returns the descriptor number found, or vq->num (which
+ * is never a valid descriptor number) if none was found. */
+unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
+ struct iovec iov[], unsigned int iov_size,
+ unsigned int *out_num, unsigned int *in_num,
+ struct vhost_log *log, unsigned int *log_num)
+{
+ struct vring_desc desc;
+ unsigned int i, head, found = 0;
+ u16 last_avail_idx;
+ int ret;
+
+ /* Check it isn't doing very strange things with descriptor numbers. */
+ last_avail_idx = vq->last_avail_idx;
+ if (get_user(vq->avail_idx, &vq->avail->idx)) {
+ vq_err(vq, "Failed to access avail idx at %p\n",
+ &vq->avail->idx);
+ return vq->num;
+ }
+
+ if ((u16)(vq->avail_idx - last_avail_idx) > vq->num) {
+ vq_err(vq, "Guest moved used index from %u to %u",
+ last_avail_idx, vq->avail_idx);
+ return vq->num;
+ }
+
+ /* If there's nothing new since last we looked, return invalid. */
+ if (vq->avail_idx == last_avail_idx)
+ return vq->num;
+
+ /* Only get avail ring entries after they have been exposed by guest. */
+ rmb();
+
+ /* Grab the next descriptor number they're advertising, and increment
+ * the index we've seen. */
+ if (get_user(head, &vq->avail->ring[last_avail_idx % vq->num])) {
+ vq_err(vq, "Failed to read head: idx %d address %p\n",
+ last_avail_idx,
+ &vq->avail->ring[last_avail_idx % vq->num]);
+ return vq->num;
+ }
+
+ /* If their number is silly, that's an error. */
+ if (head >= vq->num) {
+ vq_err(vq, "Guest says index %u > %u is available",
+ head, vq->num);
+ return vq->num;
+ }
+
+ /* When we start there are none of either input nor output. */
+ *out_num = *in_num = 0;
+ if (unlikely(log))
+ *log_num = 0;
+
+ i = head;
+ do {
+ unsigned iov_count = *in_num + *out_num;
+ if (i >= vq->num) {
+ vq_err(vq, "Desc index is %u > %u, head = %u",
+ i, vq->num, head);
+ return vq->num;
+ }
+ if (++found > vq->num) {
+ vq_err(vq, "Loop detected: last one at %u "
+ "vq size %u head %u\n",
+ i, vq->num, head);
+ return vq->num;
+ }
+ ret = copy_from_user(&desc, vq->desc + i, sizeof desc);
+ if (ret) {
+ vq_err(vq, "Failed to get descriptor: idx %d addr %p\n",
+ i, vq->desc + i);
+ return vq->num;
+ }
+ if (desc.flags & VRING_DESC_F_INDIRECT) {
+ ret = get_indirect(dev, vq, iov, iov_size,
+ out_num, in_num,
+ log, log_num, &desc);
+ if (ret < 0) {
+ vq_err(vq, "Failure detected "
+ "in indirect descriptor at idx %d\n", i);
+ return vq->num;
+ }
+ continue;
+ }
+
+ ret = translate_desc(dev, desc.addr, desc.len, iov + iov_count,
+ iov_size - iov_count);
+ if (ret < 0) {
+ vq_err(vq, "Translation failure %d descriptor idx %d\n",
+ ret, i);
+ return vq->num;
+ }
+ if (desc.flags & VRING_DESC_F_WRITE) {
+ /* If this is an input descriptor,
+ * increment that count. */
+ *in_num += ret;
+ if (unlikely(log)) {
+ log[*log_num].addr = desc.addr;
+ log[*log_num].len = desc.len;
+ ++*log_num;
+ }
+ } else {
+ /* If it's an output descriptor, they're all supposed
+ * to come before any input descriptors. */
+ if (*in_num) {
+ vq_err(vq, "Descriptor has out after in: "
+ "idx %d\n", i);
+ return vq->num;
+ }
+ *out_num += ret;
+ }
+ } while ((i = next_desc(&desc)) != -1);
+
+ /* On success, increment avail index. */
+ vq->last_avail_idx++;
+ return head;
+}
+
+/* Reverse the effect of vhost_get_vq_desc. Useful for error handling. */
+void vhost_discard_vq_desc(struct vhost_virtqueue *vq)
+{
+ vq->last_avail_idx--;
+}
+
+/* After we've used one of their buffers, we tell them about it. We'll then
+ * want to notify the guest, using eventfd. */
+int vhost_add_used(struct vhost_virtqueue *vq, unsigned int head, int len)
+{
+ struct vring_used_elem *used;
+
+ /* The virtqueue contains a ring of used buffers. Get a pointer to the
+ * next entry in that used ring. */
+ used = &vq->used->ring[vq->last_used_idx % vq->num];
+ if (put_user(head, &used->id)) {
+ vq_err(vq, "Failed to write used id");
+ return -EFAULT;
+ }
+ if (put_user(len, &used->len)) {
+ vq_err(vq, "Failed to write used len");
+ return -EFAULT;
+ }
+ /* Make sure buffer is written before we update index. */
+ wmb();
+ if (put_user(vq->last_used_idx + 1, &vq->used->idx)) {
+ vq_err(vq, "Failed to increment used idx");
+ return -EFAULT;
+ }
+ if (unlikely(vq->log_used)) {
+ /* Make sure data is seen before log. */
+ wmb();
+ log_write(vq->log_base, vq->log_addr + sizeof *vq->used->ring *
+ (vq->last_used_idx % vq->num),
+ sizeof *vq->used->ring);
+ log_write(vq->log_base, vq->log_addr, sizeof *vq->used->ring);
+ if (vq->log_ctx)
+ eventfd_signal(vq->log_ctx, 1);
+ }
+ vq->last_used_idx++;
+ return 0;
+}
+
+/* This actually signals the guest, using eventfd. */
+void vhost_signal(struct vhost_dev *dev, struct vhost_virtqueue *vq)
+{
+ __u16 flags = 0;
+ if (get_user(flags, &vq->avail->flags)) {
+ vq_err(vq, "Failed to get flags");
+ return;
+ }
+
+ /* If they don't want an interrupt, don't signal, unless empty. */
+ if ((flags & VRING_AVAIL_F_NO_INTERRUPT) &&
+ (vq->avail_idx != vq->last_avail_idx ||
+ !vhost_has_feature(dev, VIRTIO_F_NOTIFY_ON_EMPTY)))
+ return;
+
+ /* Signal the Guest tell them we used something up. */
+ if (vq->call_ctx)
+ eventfd_signal(vq->call_ctx, 1);
+}
+
+/* And here's the combo meal deal. Supersize me! */
+void vhost_add_used_and_signal(struct vhost_dev *dev,
+ struct vhost_virtqueue *vq,
+ unsigned int head, int len)
+{
+ vhost_add_used(vq, head, len);
+ vhost_signal(dev, vq);
+}
+
+/* OK, now we need to know about added descriptors. */
+bool vhost_enable_notify(struct vhost_virtqueue *vq)
+{
+ u16 avail_idx;
+ int r;
+ if (!(vq->used_flags & VRING_USED_F_NO_NOTIFY))
+ return false;
+ vq->used_flags &= ~VRING_USED_F_NO_NOTIFY;
+ r = put_user(vq->used_flags, &vq->used->flags);
+ if (r) {
+ vq_err(vq, "Failed to enable notification at %p: %d\n",
+ &vq->used->flags, r);
+ return false;
+ }
+ /* They could have slipped one in as we were doing that: make
+ * sure it's written, then check again. */
+ mb();
+ r = get_user(avail_idx, &vq->avail->idx);
+ if (r) {
+ vq_err(vq, "Failed to check avail idx at %p: %d\n",
+ &vq->avail->idx, r);
+ return false;
+ }
+
+ return avail_idx != vq->last_avail_idx;
+}
+
+/* We don't need to be notified again. */
+void vhost_disable_notify(struct vhost_virtqueue *vq)
+{
+ int r;
+ if (vq->used_flags & VRING_USED_F_NO_NOTIFY)
+ return;
+ vq->used_flags |= VRING_USED_F_NO_NOTIFY;
+ r = put_user(vq->used_flags, &vq->used->flags);
+ if (r)
+ vq_err(vq, "Failed to enable notification at %p: %d\n",
+ &vq->used->flags, r);
+}
+
+int vhost_init(void)
+{
+ vhost_workqueue = create_singlethread_workqueue("vhost");
+ if (!vhost_workqueue)
+ return -ENOMEM;
+ return 0;
+}
+
+void vhost_cleanup(void)
+{
+ destroy_workqueue(vhost_workqueue);
+}
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
new file mode 100644
index 0000000..d1f0453
--- /dev/null
+++ b/drivers/vhost/vhost.h
@@ -0,0 +1,159 @@
+#ifndef _VHOST_H
+#define _VHOST_H
+
+#include <linux/eventfd.h>
+#include <linux/vhost.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/poll.h>
+#include <linux/file.h>
+#include <linux/skbuff.h>
+#include <linux/uio.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_ring.h>
+
+struct vhost_device;
+
+enum {
+ /* Enough place for all fragments, head, and virtio net header. */
+ VHOST_NET_MAX_SG = MAX_SKB_FRAGS + 2,
+};
+
+/* Poll a file (eventfd or socket) */
+/* Note: there's nothing vhost specific about this structure. */
+struct vhost_poll {
+ poll_table table;
+ wait_queue_head_t *wqh;
+ wait_queue_t wait;
+ /* struct which will handle all actual work. */
+ struct work_struct work;
+ unsigned long mask;
+};
+
+void vhost_poll_init(struct vhost_poll *poll, work_func_t func,
+ unsigned long mask);
+void vhost_poll_start(struct vhost_poll *poll, struct file *file);
+void vhost_poll_stop(struct vhost_poll *poll);
+void vhost_poll_flush(struct vhost_poll *poll);
+void vhost_poll_queue(struct vhost_poll *poll);
+
+struct vhost_log {
+ u64 addr;
+ u64 len;
+};
+
+/* The virtqueue structure describes a queue attached to a device. */
+struct vhost_virtqueue {
+ struct vhost_dev *dev;
+
+ /* The actual ring of buffers. */
+ struct mutex mutex;
+ unsigned int num;
+ struct vring_desc __user *desc;
+ struct vring_avail __user *avail;
+ struct vring_used __user *used;
+ struct file *kick;
+ struct file *call;
+ struct file *error;
+ struct eventfd_ctx *call_ctx;
+ struct eventfd_ctx *error_ctx;
+ struct eventfd_ctx *log_ctx;
+
+ struct vhost_poll poll;
+
+ /* The routine to call when the Guest pings us, or timeout. */
+ work_func_t handle_kick;
+
+ /* Last available index we saw. */
+ u16 last_avail_idx;
+
+ /* Caches available index value from user. */
+ u16 avail_idx;
+
+ /* Last index we used. */
+ u16 last_used_idx;
+
+ /* Used flags */
+ u16 used_flags;
+
+ /* Log writes to used structure. */
+ bool log_used;
+ u64 log_addr;
+
+ struct iovec indirect[VHOST_NET_MAX_SG];
+ struct iovec iov[VHOST_NET_MAX_SG];
+ struct iovec hdr[VHOST_NET_MAX_SG];
+ size_t hdr_size;
+ /* We use a kind of RCU to access private pointer.
+ * All readers access it from workqueue, which makes it possible to
+ * flush the workqueue instead of synchronize_rcu. Therefore readers do
+ * not need to call rcu_read_lock/rcu_read_unlock: the beginning of
+ * work item execution acts instead of rcu_read_lock() and the end of
+ * work item execution acts instead of rcu_read_lock().
+ * Writers use virtqueue mutex. */
+ void *private_data;
+ /* Log write descriptors */
+ void __user *log_base;
+ struct vhost_log log[VHOST_NET_MAX_SG];
+};
+
+struct vhost_dev {
+ /* Readers use RCU to access memory table pointer
+ * log base pointer and features.
+ * Writers use mutex below.*/
+ struct vhost_memory *memory;
+ struct mm_struct *mm;
+ struct mutex mutex;
+ unsigned acked_features;
+ struct vhost_virtqueue *vqs;
+ int nvqs;
+ struct file *log_file;
+ struct eventfd_ctx *log_ctx;
+};
+
+long vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue *vqs, int nvqs);
+long vhost_dev_check_owner(struct vhost_dev *);
+long vhost_dev_reset_owner(struct vhost_dev *);
+void vhost_dev_cleanup(struct vhost_dev *);
+long vhost_dev_ioctl(struct vhost_dev *, unsigned int ioctl, unsigned long arg);
+
+unsigned vhost_get_vq_desc(struct vhost_dev *, struct vhost_virtqueue *,
+ struct iovec iov[], unsigned int iov_count,
+ unsigned int *out_num, unsigned int *in_num,
+ struct vhost_log *log, unsigned int *log_num);
+void vhost_discard_vq_desc(struct vhost_virtqueue *);
+
+int vhost_add_used(struct vhost_virtqueue *, unsigned int head, int len);
+void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
+void vhost_add_used_and_signal(struct vhost_dev *, struct vhost_virtqueue *,
+ unsigned int head, int len);
+void vhost_disable_notify(struct vhost_virtqueue *);
+bool vhost_enable_notify(struct vhost_virtqueue *);
+
+int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
+ unsigned int log_num, u64 len);
+
+int vhost_init(void);
+void vhost_cleanup(void);
+
+#define vq_err(vq, fmt, ...) do { \
+ pr_debug(pr_fmt(fmt), ##__VA_ARGS__); \
+ if ((vq)->error_ctx) \
+ eventfd_signal((vq)->error_ctx, 1);\
+ } while (0)
+
+enum {
+ VHOST_FEATURES = (1 << VIRTIO_F_NOTIFY_ON_EMPTY) |
+ (1 << VIRTIO_RING_F_INDIRECT_DESC) |
+ (1 << VHOST_F_LOG_ALL) |
+ (1 << VHOST_NET_F_VIRTIO_NET_HDR),
+};
+
+static inline int vhost_has_feature(struct vhost_dev *dev, int bit)
+{
+ unsigned acked_features = rcu_dereference(dev->acked_features);
+ return acked_features & (1 << bit);
+}
+
+#endif
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 1feed71..e210194 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -361,6 +361,7 @@ unifdef-y += uio.h
unifdef-y += unistd.h
unifdef-y += usbdevice_fs.h
unifdef-y += utsname.h
+unifdef-y += vhost.h
unifdef-y += videodev2.h
unifdef-y += videodev.h
unifdef-y += virtio_config.h
diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h
index adaf3c1..8b5f7cc 100644
--- a/include/linux/miscdevice.h
+++ b/include/linux/miscdevice.h
@@ -30,6 +30,7 @@
#define HPET_MINOR 228
#define FUSE_MINOR 229
#define KVM_MINOR 232
+#define VHOST_NET_MINOR 233
#define MISC_DYNAMIC_MINOR 255
struct device;
diff --git a/include/linux/vhost.h b/include/linux/vhost.h
new file mode 100644
index 0000000..e847f1e
--- /dev/null
+++ b/include/linux/vhost.h
@@ -0,0 +1,130 @@
+#ifndef _LINUX_VHOST_H
+#define _LINUX_VHOST_H
+/* Userspace interface for in-kernel virtio accelerators. */
+
+/* vhost is used to reduce the number of system calls involved in virtio.
+ *
+ * Existing virtio net code is used in the guest without modification.
+ *
+ * This header includes interface used by userspace hypervisor for
+ * device configuration.
+ */
+
+#include <linux/types.h>
+#include <linux/compiler.h>
+#include <linux/ioctl.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_ring.h>
+
+struct vhost_vring_state {
+ unsigned int index;
+ unsigned int num;
+};
+
+struct vhost_vring_file {
+ unsigned int index;
+ int fd; /* Pass -1 to unbind from file. */
+
+};
+
+struct vhost_vring_addr {
+ unsigned int index;
+ /* Option flags. */
+ unsigned int flags;
+ /* Flag values: */
+ /* Whether log address is valid. If set enables logging. */
+#define VHOST_VRING_F_LOG 0
+
+ /* Start of array of descriptors (virtually contiguous) */
+ __u64 desc_user_addr;
+ /* Used structure address. Must be 32 bit aligned */
+ __u64 used_user_addr;
+ /* Available structure address. Must be 16 bit aligned */
+ __u64 avail_user_addr;
+ /* Logging support. */
+ /* Log writes to used structure, at offset calculated from specified
+ * address. Address must be 32 bit aligned. */
+ __u64 log_guest_addr;
+};
+
+struct vhost_memory_region {
+ __u64 guest_phys_addr;
+ __u64 memory_size; /* bytes */
+ __u64 userspace_addr;
+ __u64 flags_padding; /* No flags are currently specified. */
+};
+
+/* All region addresses and sizes must be 4K aligned. */
+#define VHOST_PAGE_SIZE 0x1000
+
+struct vhost_memory {
+ __u32 nregions;
+ __u32 padding;
+ struct vhost_memory_region regions[0];
+};
+
+/* ioctls */
+
+#define VHOST_VIRTIO 0xAF
+
+/* Features bitmask for forward compatibility. Transport bits are used for
+ * vhost specific features. */
+#define VHOST_GET_FEATURES _IOR(VHOST_VIRTIO, 0x00, __u64)
+#define VHOST_SET_FEATURES _IOW(VHOST_VIRTIO, 0x00, __u64)
+
+/* Set current process as the (exclusive) owner of this file descriptor. This
+ * must be called before any other vhost command. Further calls to
+ * VHOST_OWNER_SET fail until VHOST_OWNER_RESET is called. */
+#define VHOST_SET_OWNER _IO(VHOST_VIRTIO, 0x01)
+/* Give up ownership, and reset the device to default values.
+ * Allows subsequent call to VHOST_OWNER_SET to succeed. */
+#define VHOST_RESET_OWNER _IO(VHOST_VIRTIO, 0x02)
+
+/* Set up/modify memory layout */
+#define VHOST_SET_MEM_TABLE _IOW(VHOST_VIRTIO, 0x03, struct vhost_memory)
+
+/* Write logging setup. */
+/* Memory writes can optionally be logged by setting bit at an offset
+ * (calculated from the physical address) from specified log base.
+ * The bit is set using an atomic 32 bit operation. */
+/* Set base address for logging. */
+#define VHOST_SET_LOG_BASE _IOW(VHOST_VIRTIO, 0x04, __u64)
+/* Specify an eventfd file descriptor to signal on log write. */
+#define VHOST_SET_LOG_FD _IOW(VHOST_VIRTIO, 0x07, int)
+
+/* Ring setup. */
+/* Set number of descriptors in ring. This parameter can not
+ * be modified while ring is running (bound to a device). */
+#define VHOST_SET_VRING_NUM _IOW(VHOST_VIRTIO, 0x10, struct vhost_vring_state)
+/* Set addresses for the ring. */
+#define VHOST_SET_VRING_ADDR _IOW(VHOST_VIRTIO, 0x11, struct vhost_vring_addr)
+/* Base value where queue looks for available descriptors */
+#define VHOST_SET_VRING_BASE _IOW(VHOST_VIRTIO, 0x12, struct vhost_vring_state)
+/* Get accessor: reads index, writes value in num */
+#define VHOST_GET_VRING_BASE _IOWR(VHOST_VIRTIO, 0x12, struct vhost_vring_state)
+
+/* The following ioctls use eventfd file descriptors to signal and poll
+ * for events. */
+
+/* Set eventfd to poll for added buffers */
+#define VHOST_SET_VRING_KICK _IOW(VHOST_VIRTIO, 0x20, struct vhost_vring_file)
+/* Set eventfd to signal when buffers have beed used */
+#define VHOST_SET_VRING_CALL _IOW(VHOST_VIRTIO, 0x21, struct vhost_vring_file)
+/* Set eventfd to signal an error */
+#define VHOST_SET_VRING_ERR _IOW(VHOST_VIRTIO, 0x22, struct vhost_vring_file)
+
+/* VHOST_NET specific defines */
+
+/* Attach virtio net ring to a raw socket, or tap device.
+ * The socket must be already bound to an ethernet device, this device will be
+ * used for transmit. Pass fd -1 to unbind from the socket and the transmit
+ * device. This can be used to stop the ring (e.g. for migration). */
+#define VHOST_NET_SET_BACKEND _IOW(VHOST_VIRTIO, 0x30, struct vhost_vring_file)
+
+/* Feature bits */
+/* Log all write descriptors. Can be changed while device is active. */
+#define VHOST_F_LOG_ALL 26
+/* vhost-net should add virtio_net_hdr for RX, and strip for TX packets. */
+#define VHOST_NET_F_VIRTIO_NET_HDR 27
+
+#endif
--
1.6.5.2.143.g8cc62
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related
* Re: [PATCH 17/11]Optimize the upload speed for PPP connection.
From: William Allen Simpson @ 2009-11-18 5:04 UTC (permalink / raw)
To: David Miller; +Cc: huananhu, netdev, linux-kernel
In-Reply-To: <20091117.034959.159359822.davem@davemloft.net>
David Miller wrote:
> From: William Allen Simpson <william.allen.simpson@gmail.com>
> Date: Tue, 17 Nov 2009 05:20:09 -0500
>
>> What David may have meant, had he followed
>> Documentation/ManagementStyle or had any project management skills
>> what-so-ever, is that you need to follow
>> Documentation/SubmittingPatches more carefully.
>
> Are personal attacks on me really necessary?
>
Actually, ironic sarcasm (juxtaposition) is a form of humor, fairly
popular on such venues as "The Daily Show". :-)
> Do you want me to look closely at your patches with a high priority
> when you submit them for inclusion?
>
Great, you're planning to start a new practice? So far, I've only been
blessed with:
* 1st contact (Oct 2):
"Otherwise asking for a is absolutely pointless as we have no
context in which to judge the code you're showing us."
The context (and entire previous patch) was pointed at by a link
in the message, and an internet-draft, but that would have required
effort (clicking and browsing).
Not exactly what I'd call "look closely at your patches"....
* 2nd contact (Oct 5), replying to my post of Oct 3:
"struct tcp_sock is already WAY TOO BIG on 64-bit systems, adding
20 more bytes to it for some odd-ball feature is not something I'm
willing to do, sorry."
Always delighted to know our work is an "odd-ball feature"....
* 3rd contact, sending private email to you as maintainer, suggested by
Andi Kleen's "On submitting kernel patches" for resolving conflicts,
and getting flamed for sending private email to you!
* Recently, flamed for re-sending a query (after waiting 30 days):
"Complaining that your work isn't getting looked at in a timely
manner will always have the exact opposite effect that you want,
it makes people have a smaller desire to look at your stuff."
Yeah, 30 days just isn't long enough.... Fortunately, Eric Dumazet
and Paul E. McKenney were really helpful (and others privately), and
I thank them again!
* 2 days ago, flamed again for re-sending a patch (after waiting 5 days),
although you'd never Ack'd or otherwise responded.
> You may be right, but that doesn't matter if you're interested in
> working together with me in the future. There are diplomatic ways to
> do everything, and this wasn't one of those ways.
>
Working *together* would be handy! But that implies cooperation and
respect -- *not* biting the newbies nor dropping the F-bomb.
^ permalink raw reply
* Re: [PATCH 2/4] [RFC] Add c/r support for connected INET sockets (v5)
From: Serge E. Hallyn @ 2009-11-18 4:34 UTC (permalink / raw)
To: Dan Smith; +Cc: containers, netdev
In-Reply-To: <1258471590-29768-3-git-send-email-danms@us.ibm.com>
Quoting Dan Smith (danms@us.ibm.com):
> This patch adds basic support for C/R of open INET sockets. I think that
> all the important bits of the TCP and ICSK socket structures is saved,
> but I think there is still some additional IPv6 stuff that needs to be
> handled.
>
> With this patch applied, the following script can be used to demonstrate
> the functionality:
>
> https://lists.linux-foundation.org/pipermail/containers/2009-October/021239.html
>
> It shows that this enables migration of a sendmail process with open
> connections from one machine to another without dropping.
>
> We probably need comments from the netdev people about the quality of
> sanity checking we do on the values in the ckpt_hdr_socket_inet
> structure on restart.
>
> Note that this still doesn't address lingering sockets yet.
>
> Changes in v5:
> - Change ckpt_write_err() to ckpt_err()
>
> Changes in v4:
> - Use the new socket buffer restore functions introduced in the
> previous patch
> - Move listen_sockets list under the restart items in ckpt_ctx
> - Rename RESTART_SOCK_LISTENONLY to RESTART_CONN_RESET
>
> Changes in v3:
> - Prevent restart from allowing a bind on a <1024 port unless the
> user is granted that capability
> - Add some sanity checking in the inet_precheck() function to make sure
> the values read from the checkpoint image are within acceptable ranges
> - Check the result of sock_restore_header_info() and fail if needed
>
> Changes in v2:
> - Restore saddr, rcv_saddr, daddr, sport, and dport from the sockaddr
> structure instead of saving them separately
> - Fix 'sock' naming in sock_cptrst()
> - Don't take the queue lock before skb_queue_tail() since it is
> done for us
> - Allow "listen only" restore behavior if RESTART_SOCK_LISTENONLY
> flag is specified on sys_restart()
> - Pull the implementation of the list of listening sockets back into
> this patch
> - Fix dangling printk
> - Add some comments around the parent/child restore logic
>
> Cc: netdev@vger.kernel.org
> Acked-by: Oren Laadan <orenl@librato.com>
> Signed-off-by: Dan Smith <danms@us.ibm.com>
Acked-by: Serge Hallyn <serue@us.ibm.com>
> ---
> checkpoint/sys.c | 4 +
> include/linux/checkpoint.h | 5 +-
> include/linux/checkpoint_hdr.h | 95 +++++++++
> include/linux/checkpoint_types.h | 1 +
> net/checkpoint.c | 27 ++--
> net/ipv4/checkpoint.c | 391 ++++++++++++++++++++++++++++++++++----
> 6 files changed, 473 insertions(+), 50 deletions(-)
>
> diff --git a/checkpoint/sys.c b/checkpoint/sys.c
> index 9f9e825..baed891 100644
> --- a/checkpoint/sys.c
> +++ b/checkpoint/sys.c
> @@ -244,6 +244,8 @@ static void ckpt_ctx_free(struct ckpt_ctx *ctx)
>
> kfree(ctx->pids_arr);
>
> + sock_listening_list_free(&ctx->listen_sockets);
> +
> kfree(ctx);
> }
>
> @@ -274,6 +276,8 @@ static struct ckpt_ctx *ckpt_ctx_alloc(int fd, unsigned long uflags,
>
> mutex_init(&ctx->msg_mutex);
>
> + INIT_LIST_HEAD(&ctx->listen_sockets);
> +
> err = -EBADF;
> ctx->file = fget(fd);
> if (!ctx->file)
> diff --git a/include/linux/checkpoint.h b/include/linux/checkpoint.h
> index 0eff43e..ddc9aa0 100644
> --- a/include/linux/checkpoint.h
> +++ b/include/linux/checkpoint.h
> @@ -20,6 +20,7 @@
> #define RESTART_FROZEN 0x2
> #define RESTART_GHOST 0x4
> #define RESTART_KEEP_LSM 0x8
> +#define RESTART_CONN_RESET 0x10
>
> /* misc user visible */
> #define CHECKPOINT_FD_NONE -1
> @@ -53,7 +54,8 @@
> (RESTART_TASKSELF | \
> RESTART_FROZEN | \
> RESTART_KEEP_LSM | \
> - RESTART_GHOST)
> + RESTART_GHOST | \
> + RESTART_CONN_RESET)
> #define CKPT_LSM_INFO_LEN 200
> #define CKPT_LSM_STRING_MAX 1024
>
> @@ -105,6 +107,7 @@ extern int ckpt_sock_getnames(struct ckpt_ctx *ctx,
> struct sockaddr *loc, unsigned *loc_len,
> struct sockaddr *rem, unsigned *rem_len);
> struct sk_buff *sock_restore_skb(struct ckpt_ctx *ctx);
> +void sock_listening_list_free(struct list_head *head);
>
> /* ckpt kflags */
> #define ckpt_set_ctx_kflag(__ctx, __kflag) \
> diff --git a/include/linux/checkpoint_hdr.h b/include/linux/checkpoint_hdr.h
> index 787cf89..d1a93e3 100644
> --- a/include/linux/checkpoint_hdr.h
> +++ b/include/linux/checkpoint_hdr.h
> @@ -15,6 +15,7 @@
> #include <linux/socket.h>
> #include <linux/un.h>
> #include <linux/in.h>
> +#include <linux/in6.h>
> #else
> #include <sys/types.h>
> #include <linux/types.h>
> @@ -625,6 +626,100 @@ struct ckpt_hdr_socket_unix {
>
> struct ckpt_hdr_socket_inet {
> struct ckpt_hdr h;
> + __u32 daddr;
> + __u32 rcv_saddr;
> + __u32 saddr;
> + __u16 dport;
> + __u16 num;
> + __u16 sport;
> + __s16 uc_ttl;
> + __u16 cmsg_flags;
> +
> + struct {
> + __u64 timeout;
> + __u32 ato;
> + __u32 lrcvtime;
> + __u16 last_seg_size;
> + __u16 rcv_mss;
> + __u8 pending;
> + __u8 quick;
> + __u8 pingpong;
> + __u8 blocked;
> + } icsk_ack __attribute__ ((aligned(8)));
> +
> + /* FIXME: Skipped opt, tos, multicast, cork settings */
> +
> + struct {
> + __u32 rcv_nxt;
> + __u32 copied_seq;
> + __u32 rcv_wup;
> + __u32 snd_nxt;
> + __u32 snd_una;
> + __u32 snd_sml;
> + __u32 rcv_tstamp;
> + __u32 lsndtime;
> +
> + __u32 snd_wl1;
> + __u32 snd_wnd;
> + __u32 max_window;
> + __u32 mss_cache;
> + __u32 window_clamp;
> + __u32 rcv_ssthresh;
> + __u32 frto_highmark;
> +
> + __u32 srtt;
> + __u32 mdev;
> + __u32 mdev_max;
> + __u32 rttvar;
> + __u32 rtt_seq;
> +
> + __u32 packets_out;
> + __u32 retrans_out;
> +
> + __u32 snd_up;
> + __u32 rcv_wnd;
> + __u32 write_seq;
> + __u32 pushed_seq;
> + __u32 lost_out;
> + __u32 sacked_out;
> + __u32 fackets_out;
> + __u32 tso_deferred;
> + __u32 bytes_acked;
> +
> + __s32 lost_cnt_hint;
> + __u32 retransmit_high;
> +
> + __u32 lost_retrans_low;
> +
> + __u32 prior_ssthresh;
> + __u32 high_seq;
> +
> + __u32 retrans_stamp;
> + __u32 undo_marker;
> + __s32 undo_retrans;
> + __u32 total_retrans;
> +
> + __u32 urg_seq;
> + __u32 keepalive_time;
> + __u32 keepalive_intvl;
> +
> + __u16 urg_data;
> + __u16 advmss;
> + __u8 frto_counter;
> + __u8 nonagle;
> +
> + __u8 ecn_flags;
> + __u8 reordering;
> +
> + __u8 keepalive_probes;
> + } tcp __attribute__ ((aligned(8)));
> +
> + struct {
> + struct in6_addr saddr;
> + struct in6_addr rcv_saddr;
> + struct in6_addr daddr;
> + } inet6 __attribute__ ((aligned(8)));
> +
> __u32 laddr_len;
> __u32 raddr_len;
> struct sockaddr_in laddr;
> diff --git a/include/linux/checkpoint_types.h b/include/linux/checkpoint_types.h
> index 77f8592..79c9c09 100644
> --- a/include/linux/checkpoint_types.h
> +++ b/include/linux/checkpoint_types.h
> @@ -82,6 +82,7 @@ struct ckpt_ctx {
> wait_queue_head_t waitq; /* waitqueue for restarting tasks */
> wait_queue_head_t ghostq; /* waitqueue for ghost tasks */
> struct cred *realcred, *ecred; /* tmp storage for cred at restart */
> + struct list_head listen_sockets;/* listening parent sockets */
>
> struct ckpt_stats stats; /* statistics */
>
> diff --git a/net/checkpoint.c b/net/checkpoint.c
> index 49d9a2f..aba1497 100644
> --- a/net/checkpoint.c
> +++ b/net/checkpoint.c
> @@ -324,6 +324,7 @@ static int __sock_write_skb(struct ckpt_ctx *ctx,
>
> static int __sock_write_buffers(struct ckpt_ctx *ctx,
> struct sk_buff_head *queue,
> + uint16_t family,
> int dst_objref)
> {
> struct sk_buff *skb;
> @@ -336,11 +337,11 @@ static int __sock_write_buffers(struct ckpt_ctx *ctx,
> return -EBUSY;
> }
>
> - /* The other ancillary messages are always present
> - * unlike descriptors. Even though we can't detect
> - * them and fail the checkpoint, we're not at risk
> - * because we don't save out (or restore) the control
> - * information contained in the skb.
> + /* The other ancillary messages UNIX are always
> + * present unlike descriptors. Even though we can't
> + * detect them and fail the checkpoint, we're not at
> + * risk because we don't restore the control
> + * information in the UNIX code.
> */
>
> ret = __sock_write_skb(ctx, skb, dst_objref);
> @@ -353,6 +354,7 @@ static int __sock_write_buffers(struct ckpt_ctx *ctx,
>
> static int sock_write_buffers(struct ckpt_ctx *ctx,
> struct sk_buff_head *queue,
> + uint16_t family,
> int dst_objref)
> {
> struct ckpt_hdr_socket_queue *h;
> @@ -372,7 +374,7 @@ static int sock_write_buffers(struct ckpt_ctx *ctx,
> h->skb_count = ret;
> ret = ckpt_write_obj(ctx, (struct ckpt_hdr *) h);
> if (!ret)
> - ret = __sock_write_buffers(ctx, &tmpq, dst_objref);
> + ret = __sock_write_buffers(ctx, &tmpq, family, dst_objref);
>
> out:
> ckpt_hdr_put(ctx, h);
> @@ -394,12 +396,14 @@ int sock_deferred_write_buffers(void *data)
> return dst_objref;
> }
>
> - ret = sock_write_buffers(ctx, &dq->sk->sk_receive_queue, dst_objref);
> + ret = sock_write_buffers(ctx, &dq->sk->sk_receive_queue,
> + dq->sk->sk_family, dst_objref);
> ckpt_debug("write recv buffers: %i\n", ret);
> if (ret < 0)
> return ret;
>
> - ret = sock_write_buffers(ctx, &dq->sk->sk_write_queue, dst_objref);
> + ret = sock_write_buffers(ctx, &dq->sk->sk_write_queue,
> + dq->sk->sk_family, dst_objref);
> ckpt_debug("write send buffers: %i\n", ret);
>
> return ret;
> @@ -924,10 +928,9 @@ struct sock *do_sock_restore(struct ckpt_ctx *ctx)
> goto err;
>
> if ((h->sock_common.family == AF_INET) &&
> - (h->sock.state != TCP_LISTEN)) {
> - /* Temporary hack to enable restore of TCP_LISTEN sockets
> - * while forcing anything else to a closed state
> - */
> + (h->sock.state != TCP_LISTEN) &&
> + (ctx->uflags & RESTART_CONN_RESET)) {
> + ckpt_debug("Forcing open socket closed\n");
> sock->sk->sk_state = TCP_CLOSE;
> sock->state = SS_UNCONNECTED;
> }
> diff --git a/net/ipv4/checkpoint.c b/net/ipv4/checkpoint.c
> index 9cbbf5e..3e20cc9 100644
> --- a/net/ipv4/checkpoint.c
> +++ b/net/ipv4/checkpoint.c
> @@ -17,6 +17,7 @@
> #include <linux/deferqueue.h>
> #include <net/tcp_states.h>
> #include <net/tcp.h>
> +#include <net/ipv6.h>
>
> struct dq_sock {
> struct ckpt_ctx *ctx;
> @@ -28,6 +29,236 @@ struct dq_buffers {
> struct sock *sk;
> };
>
> +struct listen_item {
> + struct sock *sk;
> + struct list_head list;
> +};
> +
> +void sock_listening_list_free(struct list_head *head)
> +{
> + struct listen_item *item, *tmp;
> +
> + list_for_each_entry_safe(item, tmp, head, list) {
> + list_del(&item->list);
> + kfree(item);
> + }
> +}
> +
> +static int sock_listening_list_add(struct ckpt_ctx *ctx, struct sock *sk)
> +{
> + struct listen_item *item;
> +
> + item = kmalloc(sizeof(*item), GFP_KERNEL);
> + if (!item)
> + return -ENOMEM;
> +
> + item->sk = sk;
> + list_add(&item->list, &ctx->listen_sockets);
> +
> + return 0;
> +}
> +
> +static struct sock *sock_get_parent(struct ckpt_ctx *ctx, struct sock *sk)
> +{
> + struct listen_item *item;
> +
> + list_for_each_entry(item, &ctx->listen_sockets, list) {
> + if (inet_sk(sk)->sport == inet_sk(item->sk)->sport)
> + return item->sk;
> + }
> +
> + return NULL;
> +}
> +
> +static int sock_hash_parent(void *data)
> +{
> + struct dq_sock *dq = (struct dq_sock *)data;
> + struct sock *parent;
> +
> + ckpt_debug("INET post-restart hash\n");
> +
> + dq->sk->sk_prot->hash(dq->sk);
> +
> + /* If there is a listening socket with the same source port,
> + * then become a child of that socket [we are the result of an
> + * accept()]. Otherwise hash ourselves directly in [we are
> + * the result of a connect()]
> + */
> +
> + parent = sock_get_parent(dq->ctx, dq->sk);
> + if (parent) {
> + inet_sk(dq->sk)->num = ntohs(inet_sk(dq->sk)->sport);
> + local_bh_disable();
> + __inet_inherit_port(parent, dq->sk);
> + local_bh_enable();
> + } else {
> + inet_sk(dq->sk)->num = 0;
> + inet_hash_connect(&tcp_death_row, dq->sk);
> + inet_sk(dq->sk)->num = ntohs(inet_sk(dq->sk)->sport);
> + }
> +
> + return 0;
> +}
> +
> +static int sock_defer_hash(struct ckpt_ctx *ctx, struct sock *sock)
> +{
> + struct dq_sock dq;
> +
> + dq.sk = sock;
> + dq.ctx = ctx;
> +
> + return deferqueue_add(ctx->deferqueue, &dq, sizeof(dq),
> + sock_hash_parent, NULL);
> +}
> +
> +static int sock_inet_tcp_cptrst(struct ckpt_ctx *ctx,
> + struct tcp_sock *sk,
> + struct ckpt_hdr_socket_inet *hh,
> + int op)
> +{
> + CKPT_COPY(op, hh->tcp.rcv_nxt, sk->rcv_nxt);
> + CKPT_COPY(op, hh->tcp.copied_seq, sk->copied_seq);
> + CKPT_COPY(op, hh->tcp.rcv_wup, sk->rcv_wup);
> + CKPT_COPY(op, hh->tcp.snd_nxt, sk->snd_nxt);
> + CKPT_COPY(op, hh->tcp.snd_una, sk->snd_una);
> + CKPT_COPY(op, hh->tcp.snd_sml, sk->snd_sml);
> + CKPT_COPY(op, hh->tcp.rcv_tstamp, sk->rcv_tstamp);
> + CKPT_COPY(op, hh->tcp.lsndtime, sk->lsndtime);
> +
> + CKPT_COPY(op, hh->tcp.snd_wl1, sk->snd_wl1);
> + CKPT_COPY(op, hh->tcp.snd_wnd, sk->snd_wnd);
> + CKPT_COPY(op, hh->tcp.max_window, sk->max_window);
> + CKPT_COPY(op, hh->tcp.mss_cache, sk->mss_cache);
> + CKPT_COPY(op, hh->tcp.window_clamp, sk->window_clamp);
> + CKPT_COPY(op, hh->tcp.rcv_ssthresh, sk->rcv_ssthresh);
> + CKPT_COPY(op, hh->tcp.frto_highmark, sk->frto_highmark);
> + CKPT_COPY(op, hh->tcp.advmss, sk->advmss);
> + CKPT_COPY(op, hh->tcp.frto_counter, sk->frto_counter);
> + CKPT_COPY(op, hh->tcp.nonagle, sk->nonagle);
> +
> + CKPT_COPY(op, hh->tcp.srtt, sk->srtt);
> + CKPT_COPY(op, hh->tcp.mdev, sk->mdev);
> + CKPT_COPY(op, hh->tcp.mdev_max, sk->mdev_max);
> + CKPT_COPY(op, hh->tcp.rttvar, sk->rttvar);
> + CKPT_COPY(op, hh->tcp.rtt_seq, sk->rtt_seq);
> +
> + CKPT_COPY(op, hh->tcp.packets_out, sk->packets_out);
> + CKPT_COPY(op, hh->tcp.retrans_out, sk->retrans_out);
> +
> + CKPT_COPY(op, hh->tcp.urg_data, sk->urg_data);
> + CKPT_COPY(op, hh->tcp.ecn_flags, sk->ecn_flags);
> + CKPT_COPY(op, hh->tcp.reordering, sk->reordering);
> + CKPT_COPY(op, hh->tcp.snd_up, sk->snd_up);
> +
> + CKPT_COPY(op, hh->tcp.keepalive_probes, sk->keepalive_probes);
> +
> + CKPT_COPY(op, hh->tcp.rcv_wnd, sk->rcv_wnd);
> + CKPT_COPY(op, hh->tcp.write_seq, sk->write_seq);
> + CKPT_COPY(op, hh->tcp.pushed_seq, sk->pushed_seq);
> + CKPT_COPY(op, hh->tcp.lost_out, sk->lost_out);
> + CKPT_COPY(op, hh->tcp.sacked_out, sk->sacked_out);
> + CKPT_COPY(op, hh->tcp.fackets_out, sk->fackets_out);
> + CKPT_COPY(op, hh->tcp.tso_deferred, sk->tso_deferred);
> + CKPT_COPY(op, hh->tcp.bytes_acked, sk->bytes_acked);
> +
> + CKPT_COPY(op, hh->tcp.lost_cnt_hint, sk->lost_cnt_hint);
> + CKPT_COPY(op, hh->tcp.retransmit_high, sk->retransmit_high);
> +
> + CKPT_COPY(op, hh->tcp.lost_retrans_low, sk->lost_retrans_low);
> +
> + CKPT_COPY(op, hh->tcp.prior_ssthresh, sk->prior_ssthresh);
> + CKPT_COPY(op, hh->tcp.high_seq, sk->high_seq);
> +
> + CKPT_COPY(op, hh->tcp.retrans_stamp, sk->retrans_stamp);
> + CKPT_COPY(op, hh->tcp.undo_marker, sk->undo_marker);
> + CKPT_COPY(op, hh->tcp.undo_retrans, sk->undo_retrans);
> + CKPT_COPY(op, hh->tcp.total_retrans, sk->total_retrans);
> +
> + CKPT_COPY(op, hh->tcp.urg_seq, sk->urg_seq);
> + CKPT_COPY(op, hh->tcp.keepalive_time, sk->keepalive_time);
> + CKPT_COPY(op, hh->tcp.keepalive_intvl, sk->keepalive_intvl);
> +
> + if (!skb_queue_empty(&sk->ucopy.prequeue))
> + printk("PREQUEUE!\n");
> +
> + return 0;
> +}
> +
> +static int sock_inet_restore_addrs(struct inet_sock *inet,
> + struct ckpt_hdr_socket_inet *hh)
> +{
> + inet->daddr = hh->raddr.sin_addr.s_addr;
> + inet->saddr = hh->laddr.sin_addr.s_addr;
> + inet->rcv_saddr = inet->saddr;
> +
> + inet->dport = hh->raddr.sin_port;
> + inet->sport = hh->laddr.sin_port;
> +
> + return 0;
> +}
> +
> +static int sock_inet_cptrst(struct ckpt_ctx *ctx,
> + struct sock *sk,
> + struct ckpt_hdr_socket_inet *hh,
> + int op)
> +{
> + struct inet_sock *inet = inet_sk(sk);
> + struct inet_connection_sock *icsk = inet_csk(sk);
> + int ret;
> +
> + if (op == CKPT_CPT) {
> + CKPT_COPY(op, hh->daddr, inet->daddr);
> + CKPT_COPY(op, hh->rcv_saddr, inet->rcv_saddr);
> + CKPT_COPY(op, hh->dport, inet->dport);
> + CKPT_COPY(op, hh->saddr, inet->saddr);
> + CKPT_COPY(op, hh->sport, inet->sport);
> + } else {
> + ret = sock_inet_restore_addrs(inet, hh);
> + if (ret)
> + return ret;
> + }
> +
> + CKPT_COPY(op, hh->num, inet->num);
> + CKPT_COPY(op, hh->uc_ttl, inet->uc_ttl);
> + CKPT_COPY(op, hh->cmsg_flags, inet->cmsg_flags);
> +
> + CKPT_COPY(op, hh->icsk_ack.pending, icsk->icsk_ack.pending);
> + CKPT_COPY(op, hh->icsk_ack.quick, icsk->icsk_ack.quick);
> + CKPT_COPY(op, hh->icsk_ack.pingpong, icsk->icsk_ack.pingpong);
> + CKPT_COPY(op, hh->icsk_ack.blocked, icsk->icsk_ack.blocked);
> + CKPT_COPY(op, hh->icsk_ack.ato, icsk->icsk_ack.ato);
> + CKPT_COPY(op, hh->icsk_ack.timeout, icsk->icsk_ack.timeout);
> + CKPT_COPY(op, hh->icsk_ack.lrcvtime, icsk->icsk_ack.lrcvtime);
> + CKPT_COPY(op,
> + hh->icsk_ack.last_seg_size, icsk->icsk_ack.last_seg_size);
> + CKPT_COPY(op, hh->icsk_ack.rcv_mss, icsk->icsk_ack.rcv_mss);
> +
> + if (sk->sk_protocol == IPPROTO_TCP)
> + ret = sock_inet_tcp_cptrst(ctx, tcp_sk(sk), hh, op);
> + else if (sk->sk_protocol == IPPROTO_UDP)
> + ret = 0;
> + else {
> + ret = -EINVAL;
> + ckpt_err(ctx, ret, "unknown socket protocol %d",
> + sk->sk_protocol);
> + }
> +
> + if (sk->sk_family == AF_INET6) {
> + struct ipv6_pinfo *inet6 = inet6_sk(sk);
> + if (op == CKPT_CPT) {
> + ipv6_addr_copy(&hh->inet6.saddr, &inet6->saddr);
> + ipv6_addr_copy(&hh->inet6.rcv_saddr, &inet6->rcv_saddr);
> + ipv6_addr_copy(&hh->inet6.daddr, &inet6->daddr);
> + } else {
> + ipv6_addr_copy(&inet6->saddr, &hh->inet6.saddr);
> + ipv6_addr_copy(&inet6->rcv_saddr, &hh->inet6.rcv_saddr);
> + ipv6_addr_copy(&inet6->daddr, &hh->inet6.daddr);
> + }
> + }
> +
> + return ret;
> +}
> +
> int inet_checkpoint(struct ckpt_ctx *ctx, struct socket *sock)
> {
> struct ckpt_hdr_socket_inet *in;
> @@ -43,6 +274,10 @@ int inet_checkpoint(struct ckpt_ctx *ctx, struct socket *sock)
> if (ret)
> goto out;
>
> + ret = sock_inet_cptrst(ctx, sock->sk, in, CKPT_CPT);
> + if (ret < 0)
> + goto out;
> +
> ret = ckpt_write_obj(ctx, (struct ckpt_hdr *) in);
> out:
> ckpt_hdr_put(ctx, in);
> @@ -55,51 +290,22 @@ int inet_collect(struct ckpt_ctx *ctx, struct socket *sock)
> return ckpt_obj_collect(ctx, sock->sk, CKPT_OBJ_SOCK);
> }
>
> -static int inet_read_buffer(struct ckpt_ctx *ctx, struct sk_buff_head *queue)
> +static int inet_read_buffer(struct ckpt_ctx *ctx,
> + struct sk_buff_head *queue)
> {
> - struct ckpt_hdr_socket_buffer *h;
> - int len;
> - int ret;
> struct sk_buff *skb = NULL;
>
> - h = ckpt_read_obj_type(ctx, sizeof(*h), CKPT_HDR_SOCKET_BUFFER);
> - if (IS_ERR(h))
> - return PTR_ERR(h);
> -
> - len = _ckpt_read_obj_type(ctx, NULL, 0, CKPT_HDR_BUFFER);
> - if (len < 0) {
> - ret = len;
> - goto out;
> - } else if (len > SKB_MAX_ALLOC) {
> - ckpt_debug("Socket buffer too big (%i > %lu)",
> - len, SKB_MAX_ALLOC);
> - ret = -ENOSPC;
> - goto out;
> - }
> -
> - skb = alloc_skb(len, GFP_KERNEL);
> - if (!skb) {
> - ret = -ENOMEM;
> - goto out;
> - }
> -
> - ret = ckpt_kread(ctx, skb_put(skb, len), len);
> - if (ret < 0)
> - goto out;
> + skb = sock_restore_skb(ctx);
> + if (IS_ERR(skb))
> + return PTR_ERR(skb);
>
> - spin_lock(&queue->lock);
> skb_queue_tail(queue, skb);
> - spin_unlock(&queue->lock);
> - out:
> - ckpt_hdr_put(ctx, h);
> -
> - if ((ret < 0) && skb)
> - kfree_skb(skb);
>
> - return ret;
> + return skb->len;
> }
>
> -static int inet_read_buffers(struct ckpt_ctx *ctx, struct sk_buff_head *queue)
> +static int inet_read_buffers(struct ckpt_ctx *ctx,
> + struct sk_buff_head *queue)
> {
> struct ckpt_hdr_socket_queue *h;
> int ret = 0;
> @@ -162,6 +368,19 @@ static int inet_defer_restore_buffers(struct ckpt_ctx *ctx, struct sock *sk)
>
> static int inet_precheck(struct socket *sock, struct ckpt_hdr_socket_inet *in)
> {
> + __u8 icsk_ack_mask = ICSK_ACK_SCHED | ICSK_ACK_TIMER |
> + ICSK_ACK_PUSHED | ICSK_ACK_PUSHED2;
> + __u16 urg_mask = TCP_URG_VALID | TCP_URG_NOTYET | TCP_URG_READ;
> + __u8 nonagle_mask = TCP_NAGLE_OFF | TCP_NAGLE_CORK | TCP_NAGLE_PUSH;
> + __u8 ecn_mask = TCP_ECN_OK | TCP_ECN_QUEUE_CWR | TCP_ECN_DEMAND_CWR;
> +
> + if ((htons(in->laddr.sin_port) < PROT_SOCK) &&
> + !capable(CAP_NET_BIND_SERVICE)) {
> + ckpt_debug("unable to bind to port %hu\n",
> + htons(in->laddr.sin_port));
> + return -EINVAL;
> + }
> +
> if (in->laddr_len > sizeof(struct sockaddr_in)) {
> ckpt_debug("laddr_len is too big\n");
> return -EINVAL;
> @@ -172,6 +391,77 @@ static int inet_precheck(struct socket *sock, struct ckpt_hdr_socket_inet *in)
> return -EINVAL;
> }
>
> + /* Set ato to the default */
> + in->icsk_ack.ato = TCP_ATO_MIN;
> +
> + /* No quick acks are scheduled after a restart */
> + in->icsk_ack.quick = 0;
> +
> + if (in->icsk_ack.pending & ~icsk_ack_mask) {
> + ckpt_debug("invalid pending flags 0x%x\n",
> + in->icsk_ack.pending & ~icsk_ack_mask);
> + return -EINVAL;
> + }
> +
> + if (in->icsk_ack.pingpong > 1) {
> + ckpt_debug("invalid icsk_ack.pingpong value\n");
> + return -EINVAL;
> + }
> +
> + if (in->icsk_ack.blocked > 1) {
> + ckpt_debug("invalid icsk_ack.blocked value\n");
> + return -EINVAL;
> + }
> +
> + /* do_tcp_setsockopt() quietly makes this coercion */
> + if (in->tcp.window_clamp < (SOCK_MIN_RCVBUF / 2))
> + in->tcp.window_clamp = SOCK_MIN_RCVBUF / 2;
> + else if (in->tcp.window_clamp > 65535U) {
> + ckpt_debug("invalid window_clamp value\n");
> + return -EINVAL;
> + }
> +
> + if (in->tcp.rcv_ssthresh > (4U * in->tcp.advmss))
> + in->tcp.rcv_ssthresh = 4U * in->tcp.advmss;
> +
> + /* These will all be recalculated on the next call to
> + * tcp_rtt_estimator()
> + */
> + in->tcp.srtt = in->tcp.mdev = in->tcp.mdev_max = 0;
> + in->tcp.rttvar = in->tcp.rtt_seq = 0;
> +
> + /* Might want to set packets_out to zero ? */
> +
> + if (in->tcp.rcv_wnd > MAX_TCP_WINDOW)
> + in->tcp.rcv_wnd = MAX_TCP_WINDOW;
> +
> + if (in->tcp.keepalive_intvl > MAX_TCP_KEEPINTVL) {
> + ckpt_debug("keepalive_intvl %i out of range\n",
> + in->tcp.keepalive_intvl);
> + return -EINVAL;
> + }
> +
> + if (in->tcp.keepalive_probes > MAX_TCP_KEEPCNT) {
> + ckpt_debug("Invalid keepalive_probes value %i\n",
> + in->tcp.keepalive_probes);
> + return -EINVAL;
> + }
> +
> + if (in->tcp.urg_data & ~urg_mask) {
> + ckpt_debug("Invalid urg_data value\n");
> + return -EINVAL;
> + }
> +
> + if (in->tcp.nonagle & ~nonagle_mask) {
> + ckpt_debug("Invalid nonagle value\n");
> + return -EINVAL;
> + }
> +
> + if (in->tcp.ecn_flags & ~ecn_mask) {
> + ckpt_debug("Invalid ecn_flags value\n");
> + return -EINVAL;
> + }
> +
> return 0;
> }
>
> @@ -209,8 +499,35 @@ int inet_restore(struct ckpt_ctx *ctx,
> ckpt_debug("inet listen: %i\n", ret);
> if (ret < 0)
> goto out;
> +
> + /* We are a listening socket, so add ourselves
> + * to the list of parent sockets. This will
> + * allow our children to find us later and
> + * link up
> + */
> +
> + ret = sock_listening_list_add(ctx, sock->sk);
> + if (ret < 0)
> + goto out;
> }
> } else {
> + ret = sock_inet_cptrst(ctx, sock->sk, in, CKPT_RST);
> + if (ret)
> + goto out;
> +
> + if ((h->sock.state == TCP_ESTABLISHED) &&
> + (h->sock.protocol == IPPROTO_TCP)) {
> + /* A connected socket that was spawned from an
> + * accept() needs to be hashed with its parent
> + * listening socket in order to receive
> + * traffic on the original port. Since we may
> + * not have restarted the parent yet, we defer
> + * this until later when we know we have all
> + * the listening sockets accounted for.
> + */
> + ret = sock_defer_hash(ctx, sock->sk);
> + }
> +
> if (!sock_flag(sock->sk, SOCK_DEAD))
> ret = inet_defer_restore_buffers(ctx, sock->sk);
> }
> --
> 1.6.2.5
>
> _______________________________________________
> Containers mailing list
> Containers@lists.linux-foundation.org
> https://lists.linux-foundation.org/mailman/listinfo/containers
^ permalink raw reply
* Re: [PATCH 17/11]Optimize the upload speed for PPP connection.
From: William Allen Simpson @ 2009-11-18 4:00 UTC (permalink / raw)
To: Valdis.Kletnieks; +Cc: huananhu, David Miller, netdev, linux-kernel
In-Reply-To: <13129.1258483787@turing-police.cc.vt.edu>
Valdis.Kletnieks@vt.edu wrote:
> The '-- ' *convention* isn't even at the next layer up, MIME. If anything,
> it's out at the liveware level (though some MUAs provide code to make it
> a bit easier to deal with...)
>
Hey Valdis, nice to hear from you....
> (Feel free to cite RFC chapter-and-verse if you disagree, and note that
> 'Informational' RFCs are never standards. ;)
>
Yeah, a quick check shows it's mentioned in MIME RFC-1341 (June 1992), but
certainly going back to "Proposed standard for message encapsulation"
RFC-934 (January 1985) at the very least. I seem to remember that Marshall
or Stef or somebody used it for digest sections too, but don't remember the
RFC number or a good search term.
Still, (relevance here) a convention observed for patches.
^ permalink raw reply
* Re: [RFC-PATCH] libiscsi dhcp handler
From: Rakesh Ranjan @ 2009-11-18 3:26 UTC (permalink / raw)
To: Mike Christie
Cc: open-iscsi-/JYPxA39Uh5TLH3MbocFFw, netdev-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, James.Bottomley-l3A5Bk7waGM,
David Miller, Karen Xie, Rakesh Ranjan
In-Reply-To: <4B01577E.2020003-ut6Up61K2wZBDgjK7y7TUQ@public.gmane.org>
Rakesh Ranjan wrote:
> David Miller wrote:
>> From: Rakesh Ranjan <rakesh-ut6Up61K2wZBDgjK7y7TUQ@public.gmane.org>
>> Date: Mon, 16 Nov 2009 18:41:49 +0530
>>
>>> Herein attached patches to support dhcp based provisioning for iSCSI
>>> offload capable cards. I have made dhcp code as generic as possible,
>>> please go through the code. Based on the feedback I will submit final
>>> version of these patches.
>> You can't really add objects to the build before the patch that
>> adds the source for that object.
>>
>
> Hi david,
>
> Fixed patch attached.
ping ...
--
You received this message because you are subscribed to the Google Groups "open-iscsi" group.
To post to this group, send email to open-iscsi-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
To unsubscribe from this group, send email to open-iscsi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit this group at http://groups.google.com/group/open-iscsi?hl=.
^ permalink raw reply
* Re: [RFC v2] mac80211: disallow bridging managed/adhoc interfaces
From: John W. Linville @ 2009-11-18 2:59 UTC (permalink / raw)
To: Stefan Monnier
Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <jwvy6m4bnqp.fsf-monnier+gmane.linux.kernel.wireless.general-mXXj517/zsQ@public.gmane.org>
On Tue, Nov 17, 2009 at 08:59:03PM -0500, Stefan Monnier wrote:
> > A number of people have tried to add a wireless interface
> > (in managed mode) to a bridge and then complained that it
> > doesn't work. It cannot work, however, because in 802.11
> [...]
> > To avoid such mistakes in the future, disallow adding a
> > wireless interface to a bridge.
>
> As someone who's been bitten by this, I fully support this change.
> Still, it makes me wonder: my broadcom-based home-router using the wl.o
> driver can be set in "client bridge" mode. How does it work?
If I'm not mistaken, that has a bunch of code embedded in it that
among other things can do a layer-2 version of NAT to rewrite the
MAC adresses for frames on the air.
YMMV...
John
--
John W. Linville Someday the world will need a hero, and you
linville-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org might be all we have. Be ready.
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH 2.6.32] cxgb3: fix premature page unmap
From: Divy Le Ray @ 2009-11-18 2:38 UTC (permalink / raw)
To: davem; +Cc: netdev, linux-kernel, swise
From: Divy Le Ray <divy@chelsio.com>
unmap Rx page only when guaranteed that this page won't be
used anymore to allocate rx page chunks.
Signed-off-by: Divy Le Ray <divy@chelsio.com>
---
drivers/net/cxgb3/sge.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
index f866128..6366061 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -879,7 +879,7 @@ recycle:
pci_dma_sync_single_for_cpu(adap->pdev, dma_addr, len,
PCI_DMA_FROMDEVICE);
(*sd->pg_chunk.p_cnt)--;
- if (!*sd->pg_chunk.p_cnt)
+ if (!*sd->pg_chunk.p_cnt && sd->pg_chunk.page != fl->pg_chunk.page)
pci_unmap_page(adap->pdev,
sd->pg_chunk.mapping,
fl->alloc_size,
@@ -2088,7 +2088,7 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs,
PCI_DMA_FROMDEVICE);
(*sd->pg_chunk.p_cnt)--;
- if (!*sd->pg_chunk.p_cnt)
+ if (!*sd->pg_chunk.p_cnt && sd->pg_chunk.page != fl->pg_chunk.page)
pci_unmap_page(adap->pdev,
sd->pg_chunk.mapping,
fl->alloc_size,
^ permalink raw reply related
* Re: [PATCH] Documentation, clarify tuntap IPX example.
From: andrew hendry @ 2009-11-18 2:14 UTC (permalink / raw)
To: Max Krasnyansky; +Cc: netdev@vger.kernel.org, linux-kernel
In-Reply-To: <4B035081.8040900@qualcomm.com>
Hi Max,
I started looking through the documentation because im looking to use
tun for X.25 over TCP. The IPX example sounded similar but i couldn't
get it to work as I was expecting. Looking for a hint in the right
direction.
There is an old non-mainline patch called x25tap (clone of obsolete
ethertap). I'm hoping to replace x25tap with tun.
The old x25tap creates a device like:
x25tap0 Link encap:generic X.25 HWaddr
UP BROADCAST RUNNING NOARP MULTICAST MTU:1024 Metric:1
RX packets:3040785 errors:0 dropped:0 overruns:0 frame:0
TX packets:2895530 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:10
RX bytes:138787339 (132.3 Mb) TX bytes:91395983 (87.1 Mb)
When the x25tap is loaded it has dev->type = ARPHRD_X25, after which
x.25 routing and AF_X25 sockets can be created. Along with an XoT
userspace program which handles some basic headers and TCP port 1998
it works well.
If using tun, how does something get registered to handle protocol AF_X25?
Regards,
Andrew.
On Wed, Nov 18, 2009 at 12:40 PM, Max Krasnyansky <maxk@qualcomm.com> wrote:
> On 11/17/2009 05:30 PM, andrew hendry wrote:
>>
>> Can the TUNSETIFF ioctl change a tap's protocol to IPX as the
>> documentation suggests?
>> I think tun.c would need IFF_IPX_TAP added for it to work as described?
>> Otherwise tap can only be ptp or ethernet, and there is no way to
>> route or use AF_IPX.
>
> TAP is an Ethernet device. No special handling is required for IPX or for
> that matter any other protocol. Example seems fine too.
>
> Max
>
>> Signed-off-by: Andrew Hendry<andrew.hendry@gmail.com>
>>
>> --- a/Documentation/networking/tuntap.txt 2009-11-11
>> 14:03:22.676167648 +1100
>> +++ b/Documentation/networking/tuntap.txt 2009-11-18
>> 11:34:18.106647029 +1100
>> @@ -127,12 +127,14 @@ Ethernet device, which instead of receiv
>> media, receives them from user space program and instead of sending
>> packets via physical media sends them to the user space program.
>>
>> -Let's say that you configured IPX on the tap0, then whenever
>> -the kernel sends an IPX packet to tap0, it is passed to the application
>> -(VTun for example). The application encrypts, compresses and sends it to
>> -the other side over TCP or UDP. The application on the other side
>> decompresses
>> -and decrypts the data received and writes the packet to the TAP device,
>> -the kernel handles the packet like it came from real physical device.
>> +Let's say for the purpose of example, IPX support was added to tuntap.
>> +Then whenever the kernel routes an IPX packet to tap0, it is passed to
>> the
>> +application reading the file descriptor from /dev/net/tun (VTun for
>> example).
>> +The application encrypts, compresses and sends it to the other side over
>> TCP
>> +or UDP. The application on the other side decompresses and decrypts the
>> data
>> +received and writes the packet to the TAP device, the remote kernel
>> handles
>> +the packet like it came from real physical device. The IPX applications
>> are
>> +able to communicate as if there was a real IPX network.
>>
>> 4. What is the difference between TUN driver and TAP driver?
>> TUN works with IP frames. TAP works with Ethernet frames.
>
>
^ permalink raw reply
* NETLINK sockets dont honor SO_RCVLOWAT?
From: Jeff Haran @ 2009-11-18 1:54 UTC (permalink / raw)
To: netdev
Hi,
Am I correct in my observation that the SO_RCVLOWAT socket option is not honored when one calls readv() on a PF_NETLINK socket?
The test application I wrote returns data as soon as it's available regardless of the option value I've specified and my perusal of the kernel sources leads me to believe that the NETLINK code does not honor it (support for the option appears to be protocol specific and I don't see it in the netlink code), but I could be missing something.
Please respond directly to my email address, jharan (at) brocade.com, as I do not subscribe to this list.
Thanks,
Jeff Haran
Brocade Communications
^ permalink raw reply
* Re: [RFC v2] mac80211: disallow bridging managed/adhoc interfaces
From: Stefan Monnier @ 2009-11-18 1:59 UTC (permalink / raw)
To: linux-wireless-u79uwXL29TY76Z2rM5mHXA; +Cc: netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1258490898.21197.42.camel@johannes.local>
> A number of people have tried to add a wireless interface
> (in managed mode) to a bridge and then complained that it
> doesn't work. It cannot work, however, because in 802.11
[...]
> To avoid such mistakes in the future, disallow adding a
> wireless interface to a bridge.
As someone who's been bitten by this, I fully support this change.
Still, it makes me wonder: my broadcom-based home-router using the wl.o
driver can be set in "client bridge" mode. How does it work?
Stefan
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] Documentation, clarify tuntap IPX example.
From: Max Krasnyansky @ 2009-11-18 1:40 UTC (permalink / raw)
To: andrew hendry; +Cc: netdev@vger.kernel.org, linux-kernel
In-Reply-To: <d45a3acc0911171730kc3a03d5iacec6d9ef4b1874c@mail.gmail.com>
On 11/17/2009 05:30 PM, andrew hendry wrote:
> Can the TUNSETIFF ioctl change a tap's protocol to IPX as the
> documentation suggests?
> I think tun.c would need IFF_IPX_TAP added for it to work as described?
> Otherwise tap can only be ptp or ethernet, and there is no way to
> route or use AF_IPX.
TAP is an Ethernet device. No special handling is required for IPX or
for that matter any other protocol. Example seems fine too.
Max
> Signed-off-by: Andrew Hendry<andrew.hendry@gmail.com>
>
> --- a/Documentation/networking/tuntap.txt 2009-11-11
> 14:03:22.676167648 +1100
> +++ b/Documentation/networking/tuntap.txt 2009-11-18
> 11:34:18.106647029 +1100
> @@ -127,12 +127,14 @@ Ethernet device, which instead of receiv
> media, receives them from user space program and instead of sending
> packets via physical media sends them to the user space program.
>
> -Let's say that you configured IPX on the tap0, then whenever
> -the kernel sends an IPX packet to tap0, it is passed to the application
> -(VTun for example). The application encrypts, compresses and sends it to
> -the other side over TCP or UDP. The application on the other side decompresses
> -and decrypts the data received and writes the packet to the TAP device,
> -the kernel handles the packet like it came from real physical device.
> +Let's say for the purpose of example, IPX support was added to tuntap.
> +Then whenever the kernel routes an IPX packet to tap0, it is passed to the
> +application reading the file descriptor from /dev/net/tun (VTun for example).
> +The application encrypts, compresses and sends it to the other side over TCP
> +or UDP. The application on the other side decompresses and decrypts the data
> +received and writes the packet to the TAP device, the remote kernel handles
> +the packet like it came from real physical device. The IPX applications are
> +able to communicate as if there was a real IPX network.
>
> 4. What is the difference between TUN driver and TAP driver?
> TUN works with IP frames. TAP works with Ethernet frames.
^ permalink raw reply
* [PATCH] Documentation, clarify tuntap IPX example.
From: andrew hendry @ 2009-11-18 1:30 UTC (permalink / raw)
To: maxk, netdev; +Cc: linux-kernel
Can the TUNSETIFF ioctl change a tap's protocol to IPX as the
documentation suggests?
I think tun.c would need IFF_IPX_TAP added for it to work as described?
Otherwise tap can only be ptp or ethernet, and there is no way to
route or use AF_IPX.
Signed-off-by: Andrew Hendry <andrew.hendry@gmail.com>
--- a/Documentation/networking/tuntap.txt 2009-11-11
14:03:22.676167648 +1100
+++ b/Documentation/networking/tuntap.txt 2009-11-18
11:34:18.106647029 +1100
@@ -127,12 +127,14 @@ Ethernet device, which instead of receiv
media, receives them from user space program and instead of sending
packets via physical media sends them to the user space program.
-Let's say that you configured IPX on the tap0, then whenever
-the kernel sends an IPX packet to tap0, it is passed to the application
-(VTun for example). The application encrypts, compresses and sends it to
-the other side over TCP or UDP. The application on the other side decompresses
-and decrypts the data received and writes the packet to the TAP device,
-the kernel handles the packet like it came from real physical device.
+Let's say for the purpose of example, IPX support was added to tuntap.
+Then whenever the kernel routes an IPX packet to tap0, it is passed to the
+application reading the file descriptor from /dev/net/tun (VTun for example).
+The application encrypts, compresses and sends it to the other side over TCP
+or UDP. The application on the other side decompresses and decrypts the data
+received and writes the packet to the TAP device, the remote kernel handles
+the packet like it came from real physical device. The IPX applications are
+able to communicate as if there was a real IPX network.
4. What is the difference between TUN driver and TAP driver?
TUN works with IP frames. TAP works with Ethernet frames.
^ permalink raw reply
* Re: [net-next-2.6 PATCH 1/2] ethtool: Add PHY type to ethtool get_drvinfo
From: Ben Hutchings @ 2009-11-18 1:23 UTC (permalink / raw)
To: Stephen Hemminger
Cc: Waskiewicz Jr, Peter P, Kirsher, Jeffrey T, davem@davemloft.net,
netdev@vger.kernel.org, gospo@redhat.com
In-Reply-To: <20091117164104.5da05b81@nehalam>
On Tue, 2009-11-17 at 16:41 -0800, Stephen Hemminger wrote:
> On Tue, 17 Nov 2009 11:56:57 -0800 (Pacific Standard Time)
> "Waskiewicz Jr, Peter P" <peter.p.waskiewicz.jr@intel.com> wrote:
>
> > On Tue, 17 Nov 2009, Stephen Hemminger wrote:
> >
> > > On Tue, 17 Nov 2009 08:13:24 -0800
> > > Jeff Kirsher <jeffrey.t.kirsher@intel.com> wrote:
> > >
> > > > From: PJ Waskiewicz <peter.p.waskiewicz.jr@intel.com>
> > > >
> > > > Allow the PHY type to be passed from a driver to ethtool when
> > > > ethtool -i ethX is called. With newer network cards having SFP
> > > > and SFP+ PHY cages, this information can be useful, especially
> > > > if the NIC supports hot-swapping of the PHY modules.
> > > >
> > > > Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
> > > > Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
> > > > ---
> > >
> > > Maybe revive usage of connector port in ethtool rather than adding new API?
> > > It is already there but values are out of date with current hardware.
> >
> > You're referring to the MODE_GSET port settings? If so, I like this
> > approach, and will update my patches accordingly.
>
> Yes. cmd->port is always PORT_TP or PORT_FIBRE now but could be extended
> Likewise cmd->transceiver could be modified. I haven't seen an external transceiver
> since the old fat yellow cable with vampire taps (and that was 20 yrs ago).
It seems to me there should be a transceiver type code or codes for
connectors like SFP where the bulk of the transceiver is internal but
the optical part is an external module. SFP+ is a tricky case because
it also supports passive cables.
Ben.
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* [PATCH] ibm_newemac: Fix EMACx_TRTR[TRT] bit shifts
From: Dave Mitchell @ 2009-11-18 0:56 UTC (permalink / raw)
To: netdev; +Cc: linuxppc-dev, dmitchell
The TRT bit shifts were reversed for EMAC4 and non-EMAC4 during the
port from ibm_emac to ibm_newemac. This patch corrects that error.
Signed-off-by: Dave Mitchell <dmitchell@appliedmicro.com>
Acked-by: Feng Kan <fkan@appliedmicro.com>
Acked-by: Prodyut Hazarika <phazarika@appliedmicro.com>
---
For those curious, these bits control the TX threshold.
drivers/net/ibm_newemac/emac.h | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ibm_newemac/emac.h b/drivers/net/ibm_newemac/emac.h
index d34adf9..f2751cb 100644
--- a/drivers/net/ibm_newemac/emac.h
+++ b/drivers/net/ibm_newemac/emac.h
@@ -263,8 +263,8 @@ struct emac_regs {
/* EMACx_TRTR */
-#define EMAC_TRTR_SHIFT_EMAC4 27
-#define EMAC_TRTR_SHIFT 24
+#define EMAC_TRTR_SHIFT_EMAC4 24
+#define EMAC_TRTR_SHIFT 27
/* EMAC specific TX descriptor control fields (write access) */
#define EMAC_TX_CTRL_GFCS 0x0200
--
1.6.3.2
^ permalink raw reply related
* Re: [net-next-2.6 PATCH 1/2] ethtool: Add PHY type to ethtool get_drvinfo
From: Waskiewicz Jr, Peter P @ 2009-11-18 0:47 UTC (permalink / raw)
To: Stephen Hemminger
Cc: Waskiewicz Jr, Peter P, Kirsher, Jeffrey T, davem@davemloft.net,
netdev@vger.kernel.org, gospo@redhat.com
In-Reply-To: <20091117164104.5da05b81@nehalam>
On Tue, 17 Nov 2009, Stephen Hemminger wrote:
> On Tue, 17 Nov 2009 11:56:57 -0800 (Pacific Standard Time)
> "Waskiewicz Jr, Peter P" <peter.p.waskiewicz.jr@intel.com> wrote:
>
> > On Tue, 17 Nov 2009, Stephen Hemminger wrote:
> >
> > > On Tue, 17 Nov 2009 08:13:24 -0800
> > > Jeff Kirsher <jeffrey.t.kirsher@intel.com> wrote:
> > >
> > > > From: PJ Waskiewicz <peter.p.waskiewicz.jr@intel.com>
> > > >
> > > > Allow the PHY type to be passed from a driver to ethtool when
> > > > ethtool -i ethX is called. With newer network cards having SFP
> > > > and SFP+ PHY cages, this information can be useful, especially
> > > > if the NIC supports hot-swapping of the PHY modules.
> > > >
> > > > Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
> > > > Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
> > > > ---
> > >
> > > Maybe revive usage of connector port in ethtool rather than adding new API?
> > > It is already there but values are out of date with current hardware.
> >
> > You're referring to the MODE_GSET port settings? If so, I like this
> > approach, and will update my patches accordingly.
>
> Yes. cmd->port is always PORT_TP or PORT_FIBRE now but could be extended
> Likewise cmd->transceiver could be modified. I haven't seen an external transceiver
> since the old fat yellow cable with vampire taps (and that was 20 yrs ago).
I have patches that I sent to Jeff for internal testing that fixes up the
cmd->port field (per your and Ben's suggestion). I like it much better
too. :-)
-PJ
^ permalink raw reply
* Re: [net-next-2.6 PATCH] net: device name allocation cleanups
From: Stephen Hemminger @ 2009-11-18 0:46 UTC (permalink / raw)
To: Octavian Purdila; +Cc: netdev
In-Reply-To: <200911172233.53119.opurdila@ixiacom.com>
On Tue, 17 Nov 2009 22:33:53 +0200
Octavian Purdila <opurdila@ixiacom.com> wrote:
> + if (fmt) {
> + if (strchr(name, '%'))
> + return __dev_alloc_name(net, name, buf);
> + }
> +
> + if (__dev_get_by_name(net, name))
Flatten this logic out.
if (fmt && strchr(name, '%'))
return __dev_alloc_name(net, name, buf);
else if (__dev_get_by_name(net, name))
return -EEXIST;
else if (buf != name)
strlcpy(buf, name, IFNAMSIZ);
return 0;
^ permalink raw reply
* Re: [net-next-2.6 PATCH] net: device name allocation cleanups
From: Stephen Hemminger @ 2009-11-18 0:42 UTC (permalink / raw)
To: Octavian Purdila; +Cc: netdev
In-Reply-To: <200911172233.53119.opurdila@ixiacom.com>
On Tue, 17 Nov 2009 22:33:53 +0200
Octavian Purdila <opurdila@ixiacom.com> wrote:
> +static int dev_get_valid_name(struct net *net, const char *name, char *buf,
> + int fmt)
you are using fmt as a boolean so declare it 'bool'?
--
^ permalink raw reply
* Re: [net-next-2.6 PATCH 1/2] ethtool: Add PHY type to ethtool get_drvinfo
From: Stephen Hemminger @ 2009-11-18 0:41 UTC (permalink / raw)
To: Waskiewicz Jr, Peter P
Cc: Kirsher, Jeffrey T, davem@davemloft.net, netdev@vger.kernel.org,
gospo@redhat.com, Waskiewicz Jr, Peter P
In-Reply-To: <Pine.WNT.4.64.0911171156090.15476@ppwaskie-MOBL2.amr.corp.intel.com>
On Tue, 17 Nov 2009 11:56:57 -0800 (Pacific Standard Time)
"Waskiewicz Jr, Peter P" <peter.p.waskiewicz.jr@intel.com> wrote:
> On Tue, 17 Nov 2009, Stephen Hemminger wrote:
>
> > On Tue, 17 Nov 2009 08:13:24 -0800
> > Jeff Kirsher <jeffrey.t.kirsher@intel.com> wrote:
> >
> > > From: PJ Waskiewicz <peter.p.waskiewicz.jr@intel.com>
> > >
> > > Allow the PHY type to be passed from a driver to ethtool when
> > > ethtool -i ethX is called. With newer network cards having SFP
> > > and SFP+ PHY cages, this information can be useful, especially
> > > if the NIC supports hot-swapping of the PHY modules.
> > >
> > > Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
> > > Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
> > > ---
> >
> > Maybe revive usage of connector port in ethtool rather than adding new API?
> > It is already there but values are out of date with current hardware.
>
> You're referring to the MODE_GSET port settings? If so, I like this
> approach, and will update my patches accordingly.
Yes. cmd->port is always PORT_TP or PORT_FIBRE now but could be extended
Likewise cmd->transceiver could be modified. I haven't seen an external transceiver
since the old fat yellow cable with vampire taps (and that was 20 yrs ago).
^ permalink raw reply
* [PATCH 2.6.32-rc6] drivers/net: ks8851_mll ethernet network driver
From: Choi, David @ 2009-11-17 23:02 UTC (permalink / raw)
To: davem; +Cc: netdev, linux-kernel, shemminger, greg, Choi, David
Hello all,
This patch is for ks8851 16bit MLL Ethernet network device driver in order to fix bugs and to enhance functions.
>From : David J. Choi <david.choi@micrel.com>
Summary of Changes:
-Fix to receive multicast packets by setting the corresponding hardware bit during initialization.
-Fix to re-enable the interface [by interface up command(ifup)] while the interface is down.
-Fix to down the interface by passing the last parameter correctly to request_irq().
-Remove to read 4 extra bytes from the receiving queue after reading a packet, even though it does not cause
a predictable issue now.
-Remove occurrences of transmission done interrupt in order to tx throughput enhancement.
-Enable IP checksum for packet receiving by setting the corresponding hardware bit during initialization.
-Display a message of driver name/base address on the console after driver's initialization.
-Relocate ks_enable_int()/ks_disable_int() in order not to declare those functions at the beginning of the file.
-Rename ks_enable()/_disable() to ks_enable_qmu()/ks_disable_qmu() in order to give more meaningful names
and relocate them not declaire those functions at the beginning of the file.
Signed-off-by: David J. Choi <david.choi@micrel.com>
---
--- linux-2.6.32-rc6/drivers/net/ks8851_mll.c.orig 2009-11-12 09:57:33.000000000 -0800
+++ linux-2.6.32-rc6/drivers/net/ks8851_mll.c 2009-11-17 13:43:28.000000000 -0800
@@ -568,6 +568,16 @@ static inline void ks_outblk(struct ks_n
iowrite16(*wptr++, ks->hw_addr);
}
+static void ks_disable_int(struct ks_net *ks)
+{
+ ks_wrreg16(ks, KS_IER, 0x0000);
+} /* ks_disable_int */
+
+static void ks_enable_int(struct ks_net *ks)
+{
+ ks_wrreg16(ks, KS_IER, ks->rc_ier);
+} /* ks_enable_int */
+
/**
* ks_tx_fifo_space - return the available hardware buffer size.
* @ks: The chip information
@@ -681,6 +691,47 @@ static void ks_soft_reset(struct ks_net
}
+void ks_enable_qmu(struct ks_net *ks)
+{
+ u16 w;
+
+ w = ks_rdreg16(ks, KS_TXCR);
+ /* Enables QMU Transmit (TXCR). */
+ ks_wrreg16(ks, KS_TXCR, w | TXCR_TXE);
+
+ /*
+ * RX Frame Count Threshold Enable and Auto-Dequeue RXQ Frame
+ * Enable
+ */
+
+ w = ks_rdreg16(ks, KS_RXQCR);
+ ks_wrreg16(ks, KS_RXQCR, w | RXQCR_RXFCTE);
+
+ /* Enables QMU Receive (RXCR1). */
+ w = ks_rdreg16(ks, KS_RXCR1);
+ ks_wrreg16(ks, KS_RXCR1, w | RXCR1_RXE);
+ ks->enabled = true;
+} /* ks_enable_qmu */
+
+static void ks_disable_qmu(struct ks_net *ks)
+{
+ u16 w;
+
+ w = ks_rdreg16(ks, KS_TXCR);
+
+ /* Disables QMU Transmit (TXCR). */
+ w &= ~TXCR_TXE;
+ ks_wrreg16(ks, KS_TXCR, w);
+
+ /* Disables QMU Receive (RXCR1). */
+ w = ks_rdreg16(ks, KS_RXCR1);
+ w &= ~RXCR1_RXE ;
+ ks_wrreg16(ks, KS_RXCR1, w);
+
+ ks->enabled = false;
+
+} /* ks_disable_qmu */
+
/**
* ks_read_qmu - read 1 pkt data from the QMU.
* @ks: The chip information
@@ -752,7 +803,7 @@ static void ks_rcv(struct ks_net *ks, st
(frame_hdr->len < RX_BUF_SIZE) && frame_hdr->len)) {
skb_reserve(skb, 2);
/* read data block including CRC 4 bytes */
- ks_read_qmu(ks, (u16 *)skb->data, frame_hdr->len + 4);
+ ks_read_qmu(ks, (u16 *)skb->data, frame_hdr->len);
skb_put(skb, frame_hdr->len);
skb->dev = netdev;
skb->protocol = eth_type_trans(skb, netdev);
@@ -861,7 +912,7 @@ static int ks_net_open(struct net_device
ks_dbg(ks, "%s - entry\n", __func__);
/* reset the HW */
- err = request_irq(ks->irq, ks_irq, KS_INT_FLAGS, DRV_NAME, ks);
+ err = request_irq(ks->irq, ks_irq, KS_INT_FLAGS, DRV_NAME, netdev);
if (err) {
printk(KERN_ERR "Failed to request IRQ: %d: %d\n",
@@ -869,6 +920,15 @@ static int ks_net_open(struct net_device
return err;
}
+ /* wake up powermode to normal mode */
+ ks_set_powermode(ks, PMECR_PM_NORMAL);
+ mdelay(1); /* wait for normal mode to take effect */
+
+ ks_wrreg16(ks, KS_ISR, 0xffff);
+ ks_enable_int(ks);
+ ks_enable_qmu(ks);
+ netif_start_queue(ks->netdev);
+
if (netif_msg_ifup(ks))
ks_dbg(ks, "network device %s up\n", netdev->name);
@@ -892,19 +952,14 @@ static int ks_net_stop(struct net_device
netif_stop_queue(netdev);
- kfree(ks->frame_head_info);
-
mutex_lock(&ks->lock);
/* turn off the IRQs and ack any outstanding */
ks_wrreg16(ks, KS_IER, 0x0000);
ks_wrreg16(ks, KS_ISR, 0xffff);
- /* shutdown RX process */
- ks_wrreg16(ks, KS_RXCR1, 0x0000);
-
- /* shutdown TX process */
- ks_wrreg16(ks, KS_TXCR, 0x0000);
+ /* shutdown RX/TX QMU */
+ ks_disable_qmu(ks);
/* set powermode to soft power down to save power */
ks_set_powermode(ks, PMECR_PM_SOFTDOWN);
@@ -929,17 +984,8 @@ static int ks_net_stop(struct net_device
*/
static void ks_write_qmu(struct ks_net *ks, u8 *pdata, u16 len)
{
- unsigned fid = ks->fid;
-
- fid = ks->fid;
- ks->fid = (ks->fid + 1) & TXFR_TXFID_MASK;
-
- /* reduce the tx interrupt occurrances. */
- if (!fid)
- fid |= TXFR_TXIC; /* irq on completion */
-
/* start header at txb[0] to align txw entries */
- ks->txh.txw[0] = cpu_to_le16(fid);
+ ks->txh.txw[0] = 0;
ks->txh.txw[1] = cpu_to_le16(len);
/* 1. set sudo-DMA mode */
@@ -957,16 +1003,6 @@ static void ks_write_qmu(struct ks_net *
;
}
-static void ks_disable_int(struct ks_net *ks)
-{
- ks_wrreg16(ks, KS_IER, 0x0000);
-} /* ks_disable_int */
-
-static void ks_enable_int(struct ks_net *ks)
-{
- ks_wrreg16(ks, KS_IER, ks->rc_ier);
-} /* ks_enable_int */
-
/**
* ks_start_xmit - transmit packet
* @skb : The buffer to transmit
@@ -1410,25 +1446,6 @@ static int ks_read_selftest(struct ks_ne
return ret;
}
-static void ks_disable(struct ks_net *ks)
-{
- u16 w;
-
- w = ks_rdreg16(ks, KS_TXCR);
-
- /* Disables QMU Transmit (TXCR). */
- w &= ~TXCR_TXE;
- ks_wrreg16(ks, KS_TXCR, w);
-
- /* Disables QMU Receive (RXCR1). */
- w = ks_rdreg16(ks, KS_RXCR1);
- w &= ~RXCR1_RXE ;
- ks_wrreg16(ks, KS_RXCR1, w);
-
- ks->enabled = false;
-
-} /* ks_disable */
-
static void ks_setup(struct ks_net *ks)
{
u16 w;
@@ -1463,7 +1480,7 @@ static void ks_setup(struct ks_net *ks)
w = TXCR_TXFCE | TXCR_TXPE | TXCR_TXCRC | TXCR_TCGIP;
ks_wrreg16(ks, KS_TXCR, w);
- w = RXCR1_RXFCE | RXCR1_RXBE | RXCR1_RXUE;
+ w = RXCR1_RXFCE | RXCR1_RXBE | RXCR1_RXUE | RXCR1_RXME | RXCR1_RXIPFCC;
if (ks->promiscuous) /* bPromiscuous */
w |= (RXCR1_RXAE | RXCR1_RXINVF);
@@ -1486,28 +1503,6 @@ static void ks_setup_int(struct ks_net *
ks->rc_ier = (IRQ_LCI | IRQ_TXI | IRQ_RXI);
} /* ks_setup_int */
-void ks_enable(struct ks_net *ks)
-{
- u16 w;
-
- w = ks_rdreg16(ks, KS_TXCR);
- /* Enables QMU Transmit (TXCR). */
- ks_wrreg16(ks, KS_TXCR, w | TXCR_TXE);
-
- /*
- * RX Frame Count Threshold Enable and Auto-Dequeue RXQ Frame
- * Enable
- */
-
- w = ks_rdreg16(ks, KS_RXQCR);
- ks_wrreg16(ks, KS_RXQCR, w | RXQCR_RXFCTE);
-
- /* Enables QMU Receive (RXCR1). */
- w = ks_rdreg16(ks, KS_RXCR1);
- ks_wrreg16(ks, KS_RXCR1, w | RXCR1_RXE);
- ks->enabled = true;
-} /* ks_enable */
-
static int ks_hw_init(struct ks_net *ks)
{
#define MHEADER_SIZE (sizeof(struct type_frame_head) * MAX_RECV_FRAMES)
@@ -1568,6 +1563,10 @@ static int __devinit ks8851_probe(struct
goto err_get_irq;
}
+ printk(KERN_INFO DRV_NAME
+ " hw_addr at 0x%x, hw_addr_cmd at 0x%x, irq is %d\n",
+ (int)ks->hw_addr, (int) ks->hw_addr_cmd, ks->irq);
+
ks->pdev = pdev;
mutex_init(&ks->lock);
@@ -1612,11 +1611,9 @@ static int __devinit ks8851_probe(struct
ks_soft_reset(ks, GRR_GSR);
ks_hw_init(ks);
- ks_disable(ks);
+ ks_disable_qmu(ks);
ks_setup(ks);
ks_setup_int(ks);
- ks_enable_int(ks);
- ks_enable(ks);
memcpy(netdev->dev_addr, ks->mac_addr, 6);
data = ks_rdreg16(ks, KS_OBCR);
@@ -1658,6 +1655,7 @@ static int __devexit ks8851_remove(struc
struct ks_net *ks = netdev_priv(netdev);
struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ kfree(ks->frame_head_info);
unregister_netdev(netdev);
iounmap(ks->hw_addr);
free_netdev(netdev);
--
^ permalink raw reply
* Re: [PATCH 0/3] macvlan: add vepa and bridge mode
From: Arnd Bergmann @ 2009-11-17 22:56 UTC (permalink / raw)
To: linux-kernel, Jens Osterkamp
Cc: netdev, David Miller, Stephen Hemminger, Herbert Xu,
Patrick McHardy, Patrick Mullaney, Eric W. Biederman,
Edge Virtual Bridging, Anna Fischer, bridge, Gerhard Stenzel,
virtualization
In-Reply-To: <1258497551-25959-1-git-send-email-arnd@arndb.de>
Sorry, I used the wrong address for the virtualization mailing list
at first. Please correct this to <virtualization@lists.linux-foundation.org>
when replying to the other mails.
For people only subscribed to virtualization, you can find the actual
patches at
http://patchwork.kernel.org/patch/60810/
http://patchwork.kernel.org/patch/60811/
http://patchwork.kernel.org/patch/60813/
http://patchwork.kernel.org/patch/60814/
Arnd <><
On Tuesday 17 November 2009, Arnd Bergmann wrote:
> This is based on an earlier patch from Eric Biederman adding
> forwarding between macvlans. I extended his approach to
> allow the administrator to choose the mode for each macvlan,
> and to implement a functional VEPA between macvlan.
>
> Still missing from this is support for communication between
> the lower device that the macvlans are based on. This would
> be extremely useful but as others have found out before me
> requires significant changes not only to macvlan but also
> to the common transmit path.
>
> I've seen one panic during testing this that I still need
> to track down, but it generally does what is advertised.
> I've tested VEPA operation with the hairpin support
> added to the bridge driver by Anna Fischer.
>
> My current plan is to submit this for inclusion in 2.6.33
> when people are happy with it and I tracked down any
> remaining bugs, and possibly to do the communication with
> the lower device one release later.
>
> Arnd <><
>
> ---
>
> Arnd Bergmann (3):
> macvlan: implement VEPA and private mode
> macvlan: export macvlan mode through netlink
> iplink: add macvlan options for bridge mode
>
> Eric Biederman (1):
> macvlan: Reflect macvlan packets meant for other macvlan devices
>
> linux/drivers/net/macvlan.c | 170 +++++++++++++++++++++++++++++++++-----
> linux/include/linux/if_link.h | 15 +++
> 2 files changed, 161 insertions(+), 24 deletions(-)
>
> iproute2/include/linux/if_link.h | 15 +++
> iproute2/ip/Makefile | 3 +-
> iproute2/ip/iplink_macvlan.c | 93 ++++++++++++++++++
> 3 files changed, 110 insertions(+), 1 deletions(-)
> create mode 100644 ip/iplink_macvlan.c
>
^ permalink raw reply
* Re: [patch 1/1] drivers/atm/solos-pci.c: fix warning/bug, clean up code
From: David Woodhouse @ 2009-11-17 22:55 UTC (permalink / raw)
To: akpm@linux-foundation.org
Cc: davem@davemloft.net, netdev@vger.kernel.org,
chas@cmf.nrl.navy.mil, nathan@traverse.com.au
In-Reply-To: <200911172246.nAHMkiK2004221@imap1.linux-foundation.org>
On Tue, 2009-11-17 at 14:46 -0800, akpm@linux-foundation.org wrote:
> From: Andrew Morton <akpm@linux-foundation.org>
>
> drivers/atm/solos-pci.c: In function 'flash_upgrade':
> drivers/atm/solos-pci.c:528: warning: 'fw_name' may be used uninitialized in this function
>
> Cc: Chas Williams <chas@cmf.nrl.navy.mil>
> Cc: Nathan Williams <nathan@traverse.com.au>
> Cc: David S. Miller <davem@davemloft.net>
> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Acked-By: David Woodhouse <David.Woodhouse@intel.com>
> ---
>
> drivers/atm/solos-pci.c | 29 ++++++++++++++++-------------
> 1 file changed, 16 insertions(+), 13 deletions(-)
>
> diff -puN drivers/atm/solos-pci.c~drivers-atm-solos-pcic-fix-warning-bug-clean-up-code drivers/atm/solos-pci.c
> --- a/drivers/atm/solos-pci.c~drivers-atm-solos-pcic-fix-warning-bug-clean-up-code
> +++ a/drivers/atm/solos-pci.c
> @@ -531,34 +531,37 @@ static int flash_upgrade(struct solos_ca
> int numblocks = 0;
> int offset;
>
> - if (chip == 0) {
> + switch (chip) {
> + case 0:
> fw_name = "solos-FPGA.bin";
> blocksize = FPGA_BLOCK;
> - }
> -
> - if (chip == 1) {
> + break;
> + case 1:
> fw_name = "solos-Firmware.bin";
> blocksize = SOLOS_BLOCK;
> - }
> -
> - if (chip == 2){
> + break;
> + case 2:
> if (card->fpga_version > LEGACY_BUFFERS){
> fw_name = "solos-db-FPGA.bin";
> blocksize = FPGA_BLOCK;
> } else {
> - dev_info(&card->dev->dev, "FPGA version doesn't support daughter board upgrades\n");
> + dev_info(&card->dev->dev, "FPGA version doesn't support"
> + " daughter board upgrades\n");
> return -EPERM;
> }
> - }
> -
> - if (chip == 3){
> + break;
> + case 3:
> if (card->fpga_version > LEGACY_BUFFERS){
> fw_name = "solos-Firmware.bin";
> blocksize = SOLOS_BLOCK;
> } else {
> - dev_info(&card->dev->dev, "FPGA version doesn't support daughter board upgrades\n");
> - return -EPERM;
> + dev_info(&card->dev->dev, "FPGA version doesn't support"
> + " daughter board upgrades\n");
> + return -EPERM;
> }
> + break;
> + default:
> + return -ENODEV;
> }
>
> if (request_firmware(&fw, fw_name, &card->dev->dev))
> _
--
David Woodhouse Open Source Technology Centre
David.Woodhouse@intel.com Intel Corporation
^ permalink raw reply
* [patch for 2.6.32? 2/2] hso: fix soft-lockup
From: akpm @ 2009-11-17 22:50 UTC (permalink / raw)
To: davem; +Cc: netdev, akpm, antti.kaijanmaki, greg, randy.dunlap, stable
From: Antti Kaijanmäki <antti.kaijanmaki@nomovok.com>
Fix soft-lockup in hso.c which is triggered on SMP machine when
modem is removed while file descriptor(s) under /dev are still open:
old version called kref_put() too early which resulted in destroying
hso_serial and hso_device objects which were still used later on.
Signed-off-by: Antti Kaijanmäki <antti.kaijanmaki@nomovok.com>
Cc: Greg KH <greg@kroah.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Randy Dunlap <randy.dunlap@oracle.com>
Cc: <stable@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
drivers/net/usb/hso.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff -puN drivers/net/usb/hso.c~hso-fix-soft-lockup drivers/net/usb/hso.c
--- a/drivers/net/usb/hso.c~hso-fix-soft-lockup
+++ a/drivers/net/usb/hso.c
@@ -1363,7 +1363,7 @@ static void hso_serial_close(struct tty_
/* reset the rts and dtr */
/* do the actual close */
serial->open_count--;
- kref_put(&serial->parent->ref, hso_serial_ref_free);
+
if (serial->open_count <= 0) {
serial->open_count = 0;
spin_lock_irq(&serial->serial_lock);
@@ -1383,6 +1383,8 @@ static void hso_serial_close(struct tty_
usb_autopm_put_interface(serial->parent->interface);
mutex_unlock(&serial->parent->mutex);
+
+ kref_put(&serial->parent->ref, hso_serial_ref_free);
}
/* close the requested serial port */
_
^ permalink raw reply
* Re: [RFC v2] mac80211: disallow bridging managed/adhoc interfaces
From: Julian Calaby @ 2009-11-17 22:50 UTC (permalink / raw)
To: Johannes Berg; +Cc: netdev, linux-wireless, Stephen Hemminger, Felix Fietkau
In-Reply-To: <1258498005.30511.3.camel@johannes.local>
On Wed, Nov 18, 2009 at 09:46, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Wed, 2009-11-18 at 09:42 +1100, Julian Calaby wrote:
>> On Wed, Nov 18, 2009 at 07:48, Johannes Berg <johannes@sipsolutions.net> wrote:
>> > --- wireless-testing.orig/net/mac80211/iface.c 2009-11-17 14:20:19.000000000 +0100
>> > +++ wireless-testing/net/mac80211/iface.c 2009-11-17 17:56:08.000000000 +0100
>> > @@ -745,6 +745,11 @@ int ieee80211_if_change_type(struct ieee
>> > if (type == sdata->vif.type)
>> > return 0;
>> >
>> > + /* if it's part of a bridge, reject changing type to station/ibss */
>> > + if (sdata->dev->br_port && (type == NL80211_IFTYPE_ADHOC ||
>> > + type == NL80211_IFTYPE_STATION))
>> > + return -EBUSY;
>>
>> Busy doesn't seem like the right error here ... maybe use -EOPNOTSUPP
>> like the next test?
>
> Not sure, it's a temporary error and you can fix it by removing it from
> the bridge, so it's "busy" in the sense that it is fixed to the current
> mode or any other bridging mode by being in the bridge ... it's not that
> it doesn't support the mode.
Arguably the test following this (ensuring that we don't set ad-hoc
mode on a non-ad-hoc channel) is equally temporary - i.e. both actions
require the user to do something before they'll work again.
But then, the test after that - for whether the interface is running -
returns -EBUSY - and is just as easy to remedy, so........
Thanks,
--
Julian Calaby
Email: julian.calaby@gmail.com
.Plan: http://sites.google.com/site/juliancalaby/
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox